home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.0_SDK / Source / FWIM / OHCIFWIM / OHCIFWIMIsoch.c < prev   
Encoding:
C/C++ Source or Header  |  1999-04-12  |  87.4 KB  |  2,894 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        OHCIFWIMIsoch.c
  3.  
  4.     Contains:    FireWire interface module isochronous software for OpenHCI 1394 cards.
  5.  
  6.     Version:    1.0
  7.     
  8.     Written by:    Jay Lloyd
  9.  
  10.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     File Ownership:
  13.  
  14.         DRI:                Jay Lloyd
  15.  
  16.         Other Contact:        Eric Anderson
  17.  
  18.         Technology:            FireWire
  19.  
  20.     Writers:
  21.  
  22.         (jkl)    Jay Lloyd
  23.  
  24.     Change History (most recent first):
  25.  
  26.        <FW7>     9/25/98    jkl        Added separate end of DCL label handling for isoch receive and
  27.                                     transmit. This should allow DV transmit and the CCM camera to
  28.                                     work at the same time. Changed skip address on isoch transmit to
  29.                                     redo the same descriptor instead of going to the next one to
  30.                                     make it act more Lynx like.
  31.        <FW6>     8/26/98    jkl        Moved the dummyQuad used in isoch receive from fwim data to
  32.                                     DMABuildState. Improved isoch transmit DCL compile by adding 'no
  33.                                     packet for cycle' descriptors for the labels at the end. Still
  34.                                     needs some work to keep transmit running.
  35.        <FW5>      8/9/98    jkl        Fixed a problem with packet size in isoch transfer.
  36.        <FW4>      8/7/98    jkl        Fixed UpdateDCLList functionality.
  37.        <FW3>      8/6/98    jkl        Fixed a problem in transmit deferred task where receive port was
  38.                                     being used. Changed all DebugStr to FWDebugStr.
  39.        <FW2>      8/5/98    jkl        Cleaned up some more isoch transfers. Fixed a problem with null
  40.                                     packet processing in DV output DCL.
  41.        <FW1>      8/4/98    jkl        first checked in
  42.  
  43. */
  44.  
  45. #include <DriverServices.h>
  46. #include <PCI.h>
  47. #include "FireWire.h"
  48. #include "OHCIFWIM.h"
  49.  
  50. #include <stdio.h>
  51. extern char  debugStr[256];
  52. static pascal void FWDebugStr(
  53.     ConstStr255Param            debuggerMsg);
  54. static pascal void FWDebugStr(
  55.     ConstStr255Param            debuggerMsg)
  56. {
  57. #ifdef FW_DEBUG_BUILD
  58. #if FW_DEBUG_BUILD
  59.     DebugStr (debuggerMsg);
  60. #endif
  61. #endif
  62. }
  63.  
  64. ////////////////////////////////////////////////////////////////////////////////
  65. //
  66. // Routines available to OHCIFWIM.c
  67. //
  68. OSStatus OHCIFWIMAllocateIsochPort(
  69.     FWIMAllocateIsochPortParamsPtr
  70.                                 pFWIMAllocateIsochPortParams,
  71.     UInt32                        *pCommandAcceptance);
  72.  
  73. OSStatus OHCIFWIMReleaseIsochPort (
  74.     FWIMReleaseIsochPortParamsPtr
  75.                                 pFWIMReleaseIsochPortParams,
  76.     UInt32                        *pCommandAcceptance);
  77.  
  78. OSStatus OHCIFWIMStartIsochPort (
  79.     FWIMIsochPortControlParamsPtr
  80.                                 pFWIMIsochPortControlParams,
  81.     UInt32                        *pCommandAcceptance);
  82.  
  83. OSStatus OHCIFWIMStopIsochPort (
  84.     FWIMIsochPortControlParamsPtr
  85.                                 pFWIMIsochPortControlParams,
  86.     UInt32                        *pCommandAcceptance);
  87.  
  88. void HandleIsochRxInterrupt(
  89.     FWIMDataPtr                    pFWIMData);
  90.  
  91. void HandleIsochTxInterrupt(
  92.     FWIMDataPtr                    pFWIMData);
  93.  
  94. void IsochReceiveDeferredTask(
  95.     void                        *p1,
  96.     void                        *p2);
  97.  
  98. void IsochTransmitDeferredTask(
  99.     void                        *p1,
  100.     void                        *p2);
  101.  
  102. ////////////////////////////////////////////////////////////////////////////////
  103. //
  104. // Private Routines
  105. //
  106. static Boolean IsCompilableDCLProgram(
  107.     DCLProgramID                dclProgramID);
  108.  
  109. static OSStatus CompileDCLProgram(
  110.     FWIMDataPtr                    pFWIMData,
  111.     DCLProgramID                dclProgramID,
  112.     UInt32                        dmaPortNum,
  113.     UInt32                        channelNum,
  114.     UInt32                        speed,
  115.     Boolean                        talking);
  116.  
  117. static OSStatus PrepareDCLProgramMemory(
  118.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData,
  119.     DCLCommandPtr                dclList,
  120.     UInt32                        dclListLength);
  121.  
  122. static OSStatus    AllocateDMA(
  123.     DMABuildStatePtr            pDMABuildState,
  124.     DMADescriptorPtr            *ppDMA,
  125.     PhysicalAddress                *ppDMAPhys,
  126.     UInt32                        count);
  127.  
  128. static OSStatus ReleaseIsochPort(
  129.     FWIMDataPtr                    pFWIMData,
  130.     IsochPortDataPtr            pIsochPortData);
  131.  
  132. static OSStatus DCLCompilerNotification(
  133.     DCLProgramID                dclProgramID,
  134.     UInt32                        notificationType,
  135.     DCLCommandPtr                *dclCommandList,
  136.     UInt32                        numDCLCommands);
  137.  
  138. static OSStatus DCLCompilerUpdateNotification (
  139.     DCLProgramID                dclProgramID,
  140.     DCLCommandPtr                *dclCommandList,
  141.     UInt32                        numDCLCommands);
  142.  
  143. static OSStatus DCLCompilerModifyNotification(
  144.     DCLProgramID                dclProgramID,
  145.     DCLCommandPtr                *dclCommandList,
  146.     UInt32                        numDCLCommands);
  147.  
  148. static OSStatus StartTalkingDCLProgram (
  149.     DCLProgramID                dclProgramID);
  150.  
  151. static OSStatus StopTalkingDCLProgram (
  152.     DCLProgramID                dclProgramID);
  153.  
  154. static OSStatus StartListeningDCLProgram (
  155.     DCLProgramID                dclProgramID);
  156.  
  157. static OSStatus StopListeningDCLProgram (
  158.     DCLProgramID                dclProgramID);
  159.  
  160. static OSStatus ReleaseDCLProgram (
  161.     DCLProgramID                dclProgramID);
  162.  
  163. static OSStatus AddDCL (
  164.     DMABuildStatePtr            pDMABuildState,
  165.     DCLCommandPtr                pDCLCommand,
  166.     UInt32                        speed);
  167.  
  168. static void DeallocateDMAPools (
  169.     DMAPoolDataPtr                pDMAPoolDataList);
  170.  
  171. static OSStatus AddReceivePacketStartDCL (
  172.     DMABuildStatePtr            pDMABuildState,
  173.     DCLCommandPtr                pDCLCommand);
  174.  
  175. static Boolean AddReceiveDCLInterrupt (
  176.     DCLCommandPtr                pDCLCommand,
  177.     FWIMDataPtr                    pFWIMData,
  178.     UInt32                        portNum);
  179.  
  180. static UInt32 DataMapToPhysical (
  181.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData,
  182.     Ptr                            pBuffer,
  183.     UInt32                        size,
  184.     PhysicalMappingTablePtr        returnTable);
  185.  
  186. static OSStatus AddReceivePacketDCL (
  187.     DMABuildStatePtr            pDMABuildState,
  188.     DCLCommandPtr                pDCLCommand);
  189.  
  190. static OSStatus AddTimeStampDCL(
  191.     DMABuildStatePtr            pDMABuildState,
  192.     DCLCommandPtr                pDCLCommand);
  193.  
  194. static OSStatus AddSendPacketStartDCL(
  195.     DMABuildStatePtr            pDMABuildState,
  196.     DCLCommandPtr                pDCLCommand,
  197.     UInt32                        speed);
  198.  
  199. static Boolean AddTransmitDCLInterrupt (
  200.     DCLCommandPtr                pDCLCommand,
  201.     FWIMDataPtr                    pFWIMData,
  202.     UInt32                        portNum);
  203.  
  204. static OSStatus AddSendPacketWithHeaderStartDCL(
  205.     DMABuildStatePtr            pDMABuildState,
  206.     DCLCommandPtr                pDCLCommand,
  207.     UInt32                        speed);
  208.  
  209. static OSStatus AddSendPacketDCL(
  210.     DMABuildStatePtr            pDMABuildState,
  211.     DCLCommandPtr                pDCLCommand);
  212.  
  213. static OSStatus AddCallProcDCL(
  214.     DMABuildStatePtr            pDMABuildState,
  215.     DCLCommandPtr                pDCLCommand);
  216.  
  217. static OSStatus AddUpdateDCLListDCL(
  218.     DMABuildStatePtr            pDMABuildState,
  219.     DCLCommandPtr                pDCLCommand);
  220.  
  221. static OSStatus AddJumpAddress(
  222.     DMABuildStatePtr            pDMABuildState,
  223.     DCLCommandPtr                pDCLCommand);
  224.  
  225. static OSStatus ProcessJumpDCL(
  226.     DCLJumpPtr                    pDCLJump);
  227.  
  228. static OSStatus ProcessLabelDCL(
  229.     DMABuildStatePtr            pDMABuildState,
  230.     DCLLabelPtr                    pDCLLabel,
  231.     Boolean                        talking);
  232.  
  233. static OSStatus AddSetTagSyncBitsDCL(
  234.     DMABuildStatePtr            pDMABuildState,
  235.     DCLCommandPtr                pDCLCommand);
  236.  
  237. static OSStatus UpdateDCLTimeStamp(
  238.     DCLTimeStampPtr                pDCLTimeStamp);
  239.  
  240. static OSStatus UpdateDCLReceivePacketStart(
  241.     DCLTransferPacketPtr        pDCLTransferPacket);
  242.  
  243.  
  244. ////////////////////////////////////////////////////////////////////////////////
  245. //
  246. // OHCIFWIMAllocateIsochPort
  247. //
  248. // Allocate an isochronous port.
  249. //zzz must make sure that port is not already in use.
  250. //zzz should do more error checking.
  251. //zzz we may need to keep a list of isoch port data records.
  252. //
  253. // JKL *** all of this is hard coded to just use isoch context 0 for now
  254. //
  255.  
  256. OSStatus OHCIFWIMAllocateIsochPort(
  257.     FWIMAllocateIsochPortParamsPtr
  258.                                 pFWIMAllocateIsochPortParams,
  259.     UInt32                        *pCommandAcceptance)
  260. {
  261.     OHCIRegistersPtr            pOHCIRegs;
  262.     FWIMDataPtr                    pFWIMData;
  263.     FWIMCommandParamsPtr        pFWIMCommandParams;
  264.     IsochPortDataPtr            pIsochPortData = nil;
  265.     UInt32                        dmaPortNum;
  266.     OSStatus                    status = noErr;
  267.     Boolean                        talking;
  268.  
  269. //    FWDebugStr ((ConstStr255Param) "\pOHCIFWIMAllocateIsochPort");
  270.  
  271.     // Get our internal data.
  272.     pFWIMCommandParams = &pFWIMAllocateIsochPortParams->fwimCommandParams;
  273.     pFWIMData = (FWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  274.     pOHCIRegs = pFWIMData->pOHCIRegisters;
  275.  
  276.     // Set pending command.
  277.     pFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAllocateIsochPortParams;
  278.     pFWIMData->pendingFWIMCommandStatus = kPendingFWIMCommandBusy;
  279.  
  280.     // Are we talking?
  281.     talking = pFWIMAllocateIsochPortParams->talking;
  282.  
  283.     // Get dma channel number.
  284.     if (talking)
  285.         dmaPortNum = kIsochTransmitPort;
  286.     else
  287.         dmaPortNum = kIsochReceivePort;
  288.  
  289.     // Create an isoch port data record.
  290.     pIsochPortData = (IsochPortDataPtr) PoolAllocateResident(sizeof(IsochPortData), true);
  291.     if (pIsochPortData != nil)
  292.     {
  293.         pFWIMData->isochPortDataList[dmaPortNum] = pIsochPortData;
  294.         pIsochPortData->originalDCLProgramID = pFWIMAllocateIsochPortParams->dclProgramID;
  295.         pIsochPortData->translatedDCLProgramID = (DCLProgramID) kInvalidDCLProgramID;
  296.         pIsochPortData->channelNum = pFWIMAllocateIsochPortParams->channelNum;
  297.         pIsochPortData->speed = pFWIMAllocateIsochPortParams->speed;
  298.         pIsochPortData->talking = talking;
  299.     }
  300.     else
  301.     {
  302.         status = memFullErr;
  303.     }
  304.     
  305.     // Compile a DMA program from DCL program.
  306.     if (status == noErr)
  307.     {
  308.         // Check if program must be translated.
  309.         if (IsCompilableDCLProgram(pIsochPortData->originalDCLProgramID))
  310.         {
  311.             pIsochPortData->dclProgramID = pIsochPortData->originalDCLProgramID;
  312.         }
  313.         else
  314.         {
  315.             //zzz need to be able to deallocate this.
  316.             status = FWTranslateDCLProgram(pIsochPortData->originalDCLProgramID,
  317.                                            &(pIsochPortData->translatedDCLProgramID));
  318.             if (status == noErr)
  319.                 pIsochPortData->dclProgramID = pIsochPortData->translatedDCLProgramID;
  320.         }
  321.         
  322.         // Compile the DCL program.
  323.         if (status == noErr)
  324.         {
  325.             status = CompileDCLProgram(pFWIMData,
  326.                                         pIsochPortData->dclProgramID,
  327.                                         dmaPortNum,
  328.                                         pIsochPortData->channelNum,
  329.                                         pIsochPortData->speed,
  330.                                         talking);
  331.         }
  332.  
  333.         // Set start, stop, and release procedures for DCL program.
  334.         if (status == noErr)
  335.         {
  336.             if (talking)
  337.             {
  338.                 FWSetDCLProgramStartProc(pIsochPortData->dclProgramID,
  339.                                          StartTalkingDCLProgram);
  340.                 FWSetDCLProgramStopProc(pIsochPortData->dclProgramID,
  341.                                         StopTalkingDCLProgram);
  342.                 FWSetDCLProgramReleaseProc(pIsochPortData->dclProgramID,
  343.                                            ReleaseDCLProgram);
  344.             }
  345.             else
  346.             {
  347.                 FWSetDCLProgramStartProc(pIsochPortData->dclProgramID,
  348.                                          StartListeningDCLProgram);
  349.                 FWSetDCLProgramStopProc(pIsochPortData->dclProgramID,
  350.                                         StopListeningDCLProgram);
  351.                 FWSetDCLProgramReleaseProc(pIsochPortData->dclProgramID,
  352.                                            ReleaseDCLProgram);
  353.             }
  354.         }
  355.     }
  356.  
  357.     // Set up appropriate DMA context.
  358.     if (status == noErr)
  359.     {
  360.         if (talking)
  361.         {
  362.             // Quiet the DMA context.
  363.             // JKL *** is this the right thing to do?
  364.             pOHCIRegs->isochTxContext[kITContext0].controlClear = 0xffffffff;
  365.             SynchronizeIO ();
  366.         }
  367.  
  368.         // Set up context to receive on this port's channel.
  369.         if (!talking)
  370.         {
  371.             IRDMAContextPtr        pIRContext = &pOHCIRegs->isochRxContext[kIRContext0];
  372.             
  373.             // Quiet the DMA context.
  374.             pIRContext->controlClear = 0xffffffff;
  375.             
  376.             // want packet per buffer and isoch headers
  377.              pIRContext->controlSet = EndianSwapImm32Bit(kIRDMAIsochHeader);
  378.  
  379.             pIRContext->match = EndianSwapImm32Bit(kIRDMATag0 | kIRDMATag1 | kIRDMATag2 | kIRDMATag3 |
  380.                                                    pIsochPortData->channelNum);
  381.             SynchronizeIO ();
  382.         }
  383.  
  384.         // Set our data for port.
  385.         pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData = (UInt32) pIsochPortData;
  386.     }
  387.  
  388.     // Clean up on error.
  389.     if (status != noErr)
  390.     {
  391.         if (pIsochPortData != nil)
  392.             ReleaseIsochPort(pFWIMData, pIsochPortData);
  393.     }
  394.  
  395.     // Complete FWIM command.
  396.     pFWIMData->pPendingFWIMCommand = nil;
  397.     FWIMCommandIsComplete(pFWIMCommandParams->fwimCommandID, status);
  398.  
  399.     // Return command acceptance.
  400.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  401.  
  402.     return status;
  403. }
  404.  
  405.  
  406. ////////////////////////////////////////////////////////////////////////////////
  407. //
  408. // OHCIFWIMReleaseIsochPort
  409. //
  410. // Release resources allocated for the given isochronous port.
  411. //
  412.  
  413. OSStatus OHCIFWIMReleaseIsochPort(
  414.     FWIMReleaseIsochPortParamsPtr
  415.                                 pFWIMReleaseIsochPortParams,
  416.     UInt32                        *pCommandAcceptance)
  417. {
  418.     FWIMCommandParamsPtr        pFWIMCommandParams;
  419.     FWIMDataPtr                    pFWIMData;
  420.     IsochPortDataPtr            pIsochPortData;
  421.     OSStatus                    status = noErr;
  422.  
  423.     // Get our internal data.
  424.     pFWIMCommandParams = &pFWIMReleaseIsochPortParams->fwimCommandParams;
  425.     pFWIMData = (FWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  426.  
  427.     // Set pending command.
  428.     pFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMReleaseIsochPortParams;
  429.     pFWIMData->pendingFWIMCommandStatus = kPendingFWIMCommandBusy;
  430.  
  431.     // Get isoch port data.
  432.     pIsochPortData = (IsochPortDataPtr)
  433.         pFWIMReleaseIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
  434.  
  435.     // Release resources for isoch port.
  436.     if (pIsochPortData != nil)
  437.         status = ReleaseIsochPort(pFWIMData, pIsochPortData);
  438.  
  439.     // Complete FWIM command.
  440.     pFWIMData->pPendingFWIMCommand = nil;
  441.     FWIMCommandIsComplete(pFWIMCommandParams->fwimCommandID, status);
  442.  
  443.     // Return command acceptance.
  444.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  445.  
  446.     return status;
  447. }
  448.  
  449.  
  450. ////////////////////////////////////////////////////////////////////////////////
  451. //
  452. // OHCIFWIMStartIsochPort
  453. //
  454. // Start up the given isochronous port on the given sync event using the
  455. // given buffer.
  456. //
  457.  
  458. OSStatus OHCIFWIMStartIsochPort(
  459.     FWIMIsochPortControlParamsPtr
  460.                                 pFWIMIsochPortControlParams,
  461.     UInt32                        *pCommandAcceptance)
  462. {
  463.     FWIMCommandParamsPtr        pFWIMCommandParams;
  464.     FWIMDataPtr                    pFWIMData;
  465.     IsochPortDataPtr            pIsochPortData;
  466.     OSStatus                    status = noErr;
  467.  
  468.     // Get our internal data.
  469.     pFWIMCommandParams = &pFWIMIsochPortControlParams->fwimCommandParams;
  470.     pFWIMData = (FWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  471.  
  472.     // Set pending command.
  473.     pFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
  474.     pFWIMData->pendingFWIMCommandStatus = kPendingFWIMCommandBusy;
  475.  
  476.     // Get isoch port data.
  477.     pIsochPortData = (IsochPortDataPtr)
  478.         pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
  479.  
  480.     // Start DCL program.
  481.     if (status == noErr)
  482.         status = FWStartDCLProgram(pIsochPortData->originalDCLProgramID);
  483.  
  484.     // Finish up command.
  485.     pFWIMData->pPendingFWIMCommand = nil;
  486.     FWIMCommandIsComplete(pFWIMCommandParams->fwimCommandID, status);
  487.  
  488.     // Return command acceptance.
  489.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  490.  
  491.     return status;
  492. }
  493.  
  494.  
  495. ////////////////////////////////////////////////////////////////////////////////
  496. //
  497. // OHCIFWIMStopIsochPort
  498. //
  499. // Stop the given isochronous port on the given sync event.
  500. //
  501.  
  502. OSStatus OHCIFWIMStopIsochPort(
  503.     FWIMIsochPortControlParamsPtr
  504.                                 pFWIMIsochPortControlParams,
  505.     UInt32                        *pCommandAcceptance)
  506. {
  507.     FWIMCommandParamsPtr        pFWIMCommandParams;
  508.     FWIMDataPtr                    pFWIMData;
  509.     IsochPortDataPtr            pIsochPortData;
  510.     OSStatus                    status = noErr;
  511.  
  512.     // Get our internal data.
  513.     pFWIMCommandParams = &pFWIMIsochPortControlParams->fwimCommandParams;
  514.     pFWIMData = (FWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  515.  
  516.     // Set pending command.
  517.     pFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
  518.     pFWIMData->pendingFWIMCommandStatus = kPendingFWIMCommandBusy;
  519.  
  520.     // Get isoch port data.
  521.     pIsochPortData = (IsochPortDataPtr)
  522.         pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
  523.  
  524.     // Stop DCL program.
  525.     if (status == noErr)
  526.         status = FWStopDCLProgram(pIsochPortData->originalDCLProgramID);
  527.  
  528.     // Finish up command.
  529.     pFWIMData->pPendingFWIMCommand = nil;
  530.     FWIMCommandIsComplete(pFWIMCommandParams->fwimCommandID, status);
  531.  
  532.     // Return command acceptance.
  533.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  534.  
  535.     return status;
  536. }
  537.  
  538.  
  539. ////////////////////////////////////////////////////////////////////////////////
  540. //
  541. // IsCompilableDCLProgram
  542. //
  543. // Determine if the given DCL program is compilable.
  544. //zzz a table and range check may be faster.
  545. //zzz should do better checking.
  546. //zzz maybe we should make this determination in a first pass compilation.
  547. //
  548.  
  549. static Boolean IsCompilableDCLProgram(
  550.     DCLProgramID                dclProgramID)
  551. {
  552.     DCLCommandPtr                pDCLCommand;
  553.     Boolean                        isCompilable = true;
  554.     UInt32                        opcode;
  555.     OSStatus                    status = noErr;
  556.     
  557.     // Get first DCL in program.
  558.     status = FWGetDCLProgramStart(dclProgramID, &pDCLCommand);
  559.     if (status != noErr)
  560.         isCompilable = false;
  561.  
  562.     // Check each DCL in program.
  563.     while (isCompilable && (pDCLCommand != nil))
  564.     {
  565.         opcode = pDCLCommand->opcode;
  566.         opcode &= ~kFWDCLOpDynamicFlag;  // We can compile dynamic opcodes.
  567.         switch (opcode)
  568.         {
  569.             case kDCLReceivePacketStartOp :
  570.                 break;
  571.  
  572.             case kDCLReceivePacketOp :
  573.                 break;
  574.  
  575.             case kDCLSendPacketStartOp :
  576.                 break;
  577.  
  578.             case kDCLSendPacketWithHeaderStartOp :
  579.                 break;
  580.  
  581.             case kDCLSendPacketOp :
  582.                 break;
  583.  
  584.             case kDCLCallProcOp :
  585.                 break;
  586.  
  587.             case kDCLJumpOp :
  588.                 break;
  589.  
  590.             case kDCLLabelOp :
  591.                 break;
  592.  
  593.             case kDCLSetTagSyncBitsOp :
  594.                 break;
  595.  
  596.             case kDCLUpdateDCLListOp :
  597.                 break;
  598.  
  599.             case kDCLTimeStampOp :
  600.                 break;
  601.  
  602.             default :
  603.                 isCompilable = false;
  604.                 break;
  605.         }
  606.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  607.     }
  608.     return isCompilable;
  609. }
  610.  
  611.  
  612. ////////////////////////////////////////////////////////////////////////////////
  613. //
  614. // CompileDCLProgram
  615. //
  616. // Compile the given DCL program into a DMA program.
  617. //zzz need to set proper speed.
  618. //
  619.  
  620. static OSStatus CompileDCLProgram(
  621.     FWIMDataPtr                    pFWIMData,
  622.     DCLProgramID                dclProgramID,
  623.     UInt32                        dmaPortNum,
  624.     UInt32                        channelNum,
  625.     UInt32                        speed,
  626.     Boolean                        talking)
  627. {
  628.     DMABuildStatePtr            pDMABuildState = nil;
  629.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData = nil;
  630.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  631.     DCLCommandPtr                pDCLCommand,
  632.                                 dclList;
  633.     UInt32                        startEvent,
  634.                                 startEventState,
  635.                                 startEventStateMask;
  636.     UInt32                        dclListLength;
  637.     OSStatus                    status = noErr;
  638.  
  639.     // Create DCL engine data record.
  640.     pDCLCompilerEngineData =
  641.             (DCLCompilerEngineDataPtr) PoolAllocateResident(sizeof(DCLCompilerEngineData), true);
  642.     if (pDCLCompilerEngineData == nil)
  643.         status = memFullErr;
  644.     else
  645.         pDCLCompilerEngineData->pFWIMData = pFWIMData;
  646.         
  647.     // Initialize interrupt list.
  648.     if (status == noErr)
  649.         pFWIMData->numDCLInterrupts[dmaPortNum] = 0;
  650.         
  651.     // Set compiler notification proc.
  652.     if (status == noErr)
  653.         status = FWSetDCLProgramCompilerNotificationProc(dclProgramID, DCLCompilerNotification);
  654.  
  655.     // Get DCL list from program.
  656.     if (status == noErr)
  657.         status = FWGetDCLProgramStart(dclProgramID, &dclList);
  658.  
  659.     // Count the DCLs.
  660.     if (status == noErr)
  661.     {
  662.         pDCLCommand = dclList;
  663.         dclListLength = 0;
  664.         while (pDCLCommand != nil)
  665.         {
  666.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  667.             dclListLength++;
  668.         }
  669.     }
  670.  
  671.     // Allocate compiler data structures for all DCLs
  672.     if (status == noErr)
  673.     {
  674.         pDCLCompilerDCLData = PoolAllocateResident(dclListLength * sizeof(DCLCompilerDCLData), true);
  675.         if (pDCLCompilerDCLData == nil)
  676.         {
  677.             status = memFullErr;
  678.         }
  679.         else
  680.         {
  681.             pDCLCompilerEngineData->pDCLCompilerDCLData = pDCLCompilerDCLData;
  682.             // Assign compiler data storage to each DCL
  683.             pDCLCommand = dclList;
  684.             while (pDCLCommand != nil)
  685.             {
  686.                 pDCLCommand->compilerData = (UInt32) pDCLCompilerDCLData;
  687.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  688.                 pDCLCompilerDCLData++;
  689.             }
  690.         }
  691.     }
  692.  
  693.     // The plan is to, before compiling, scan the program to locate all data
  694.     // buffers. Then we'll prepare VM mappings for them all at once. Then
  695.     // during compilation we can look up the logical->physical mappings.
  696.     //
  697.     // A complication is that we may receive notification that a running
  698.     // program has had its buffers changed. We get a list of changes. In
  699.     // that case we need to prepare the new buffers for DMA and change the
  700.     // pointers in the descriptors, possibly expanding them if there are more
  701.     // page crossings than before. (or maybe not)
  702.     //
  703.     // When we update buffers, some may be unchanged, so we can't clear the
  704.     // original PrepareMemoryForIO. Buffers can be updated repeatedly, and
  705.     // we could pile up unlimited ioPrep structures. So we use a brute-force
  706.     // solution (NYI) and redo the *entire* ioPrep, not just the changed buffers.
  707.     // Then we can free (CheckpointIO) the original one, and all live buffers
  708.     // are still covered. (There is room for optimizations in that process.)
  709.     //
  710.     // The first time we prepare memory, we have the luxury that the program
  711.     // is not running. When we do updates, the program *is* running. But maybe
  712.     // we can use the same code both times, somehow.
  713.     
  714.     if (status == noErr)
  715.         status = PrepareDCLProgramMemory(pDCLCompilerEngineData,
  716.                                          dclList,
  717.                                          dclListLength);
  718.  
  719.     // Check if there's a start event, add it and cycle count to data.
  720.     if (status == noErr)
  721.     {
  722.         status = FWGetDCLProgramStartEvent(dclProgramID, &startEvent,
  723.                                            &startEventState, &startEventStateMask);
  724.     
  725.         if ((status == noErr) && (startEvent == kFWDCLCycleEvent))
  726.         {
  727.             pDCLCompilerEngineData->startEvent = startEvent;
  728.             
  729.             // set cycle value, ignore offset field
  730.             pDCLCompilerEngineData->startEventState =
  731.                 (startEventState & startEventStateMask) >> kCycleOffsetPhase;        
  732.         }
  733.     }
  734.  
  735.     // Allocate DMA build state record.
  736.     pDMABuildState = (DMABuildStatePtr) PoolAllocateResident(sizeof(DMABuildState), true);
  737.     if (pDMABuildState == nil)
  738.         status = memFullErr;
  739.     else
  740.     {
  741.         pDMABuildState->pFWIMData = pFWIMData;
  742.         pDMABuildState->pDCLCompilerEngineData = pDCLCompilerEngineData;
  743.         pDMABuildState->dmaPortNum = dmaPortNum;
  744.         pDMABuildState->isochChannelNum = channelNum;
  745.     }
  746.  
  747.     // Process all DCLs except label and jumps.
  748.     pDCLCommand = dclList;
  749.     while ((pDCLCommand != nil) && (status == noErr))
  750.     {
  751.         status = AddDCL(pDMABuildState, pDCLCommand, speed);
  752.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  753.     }
  754.  
  755.     // Process the label DCLs.
  756.     pDCLCommand = dclList;
  757.     while ((pDCLCommand != nil) && (status == noErr))
  758.     {
  759.         if ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
  760.             status = ProcessLabelDCL(pDMABuildState, (DCLLabelPtr) pDCLCommand, talking);
  761.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  762.     }
  763.  
  764.     // Process the jump DCLs.
  765.     pDCLCommand = dclList;
  766.     while ((pDCLCommand != nil) && (status == noErr))
  767.     {
  768.         if ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLJumpOp)
  769.             status = ProcessJumpDCL((DCLJumpPtr) pDCLCommand);
  770.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  771.     }
  772.  
  773. // JKL *** do we need to do this? make sure it is handled in the DMA program
  774. //    either InputMore with Z=0, or OutputLast* with Z=0 
  775. //
  776. //     if (status == noErr)
  777. //         status = AddStopDCL (pDMABuildState);
  778.  
  779.     // Fill in rest of DCL engine data record.
  780.     if (status == noErr)
  781.     {
  782.         pDCLCompilerEngineData->pDMAPoolDataList = pDMABuildState->pDMAPoolDataList;
  783.     }
  784.     
  785.     // Save engine data.
  786.     if (status == noErr)
  787.         status = FWSetDCLProgramEngineData(dclProgramID, (UInt32) pDCLCompilerEngineData);
  788.     
  789.     // Clean up on error.
  790.     if (status != noErr)
  791.     {
  792.         // Deallocate DMA pools.
  793.         if (pDMABuildState != nil)
  794.             if (pDMABuildState->pDMAPoolDataList != nil)
  795.                 DeallocateDMAPools(pDMABuildState->pDMAPoolDataList);
  796.  
  797.         // Deallocate compiler DCL data.
  798.         if (pDCLCompilerEngineData != nil)
  799.             if (pDCLCompilerEngineData->pDCLCompilerDCLData != nil)
  800.                 PoolDeallocate((Ptr) pDCLCompilerEngineData->pDCLCompilerDCLData);
  801.  
  802.         // Deallocate engine data.
  803.         if (pDCLCompilerEngineData != nil)
  804.             PoolDeallocate((Ptr) pDCLCompilerEngineData);
  805.     }
  806.  
  807.     // Clean up.
  808.     if (pDMABuildState != nil)
  809.         PoolDeallocate((Ptr) pDMABuildState);
  810.  
  811.     return status;
  812. }
  813.  
  814.  
  815. ////////////////////////////////////////////////////////////////////////////////
  816. //
  817. // DCLCompilerModifyNotification
  818. //
  819. // Handle modification notifications for the DCL to DMA compiler.
  820. //zzz break this routine up
  821. //
  822.  
  823. static OSStatus DCLCompilerModifyNotification(
  824.     DCLProgramID                dclProgramID,
  825.     DCLCommandPtr                *dclCommandList,
  826.     UInt32                        numDCLCommands)
  827. {
  828.     DCLCommandPtr                pDCLCommand;
  829.     UInt32                        dclCommandNum;
  830.     OSStatus                    status = noErr;
  831.  
  832.     for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
  833.     {
  834.         // Get DCL command to update.
  835.         pDCLCommand = *dclCommandList++;
  836.  
  837.         // Update command.
  838.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  839.         {
  840.             case kDCLJumpOp :
  841.                 ProcessJumpDCL((DCLJumpPtr) pDCLCommand);
  842.                 break;
  843.  
  844.             case kDCLSendPacketWithHeaderStartOp :
  845.                 //zzz support other transfer packet commands.
  846.                 FWDebugStr((ConstStr255Param) "/pOops, tried to update buffer, don't know how!");
  847.                 break;
  848.  
  849. // Some notes from LynxFWIM ...
  850. // What would we do?
  851. // We can't do what's done below - that fills in new PCL buffer addresses.  They aren't yet known.
  852. // What we want is a PrepareMemoryForIO that covers all buffers in the new scheme.  I notice that
  853. // we don't actually modify the base DCLs - I think we will have to do that.  So make one pass to
  854. // modify the base DCLs.  Then call the general-purpose memory preparation routine, and let it
  855. // create an all-new ioPrep (keep the old one).  Once that's done, we can re-scan the list of
  856. // changes and make updates knowing the new physical addresses.  Finally, once the updates are
  857. // all in place, it's impossible for any stale DMA to take place, so we can CheckpointIO on
  858. // the old ioPrep struct and free its resources.  [Technically we should wait one packet to make
  859. // sure that whatever Lynx's current DMA engine is doing is up to date.  Probably a good-enough
  860. // way to do this is to postpone the CheckpointIO until before the NEXT round of updates, though
  861. // that is somewhat wasteful if it ties down old buffers that aren't in use anymore...]
  862. //
  863. // We should find a safe way to make multiple updates to a PCL.  The user is in trouble anyway
  864. // if we're changing a PCL while it runs, because they'll get the wrong data, but we want to
  865. // make sure we don't send an illegally large packet (bad for 1394 bus) or overflow our receiver
  866. // (could be bad for Lynx).  Perhaps we should copy command[0], set it to NOP+last, update the
  867. // others, then update command[0].  That's safe unless we are inside the PCL but past command[0].
  868. // After we set command[0] to NOP, we can check the DMA current cmd and make sure it is elsewhere.
  869. //
  870. // I don't suppose the user is required to use jump-updates to deactivate part of the program
  871. // before updating that part?  That would be 100% safe if we know the jump-update worked on time.
  872. //
  873. // For safety we should probably pre-allocate a physAddr table and a rangeTable for two ioPrep
  874. // structs, then we don't have to do any allocs here.  (though PrepareMemForIO might anyway).
  875. // We know that the total number of buffers can't change, so rangeTable is OK.  When we prepare
  876. // the physAddr table we should work out both the true size and the worst-case size.  Use the
  877. // worst-case for alloc, use the true for PrepareMemoryForIO
  878. // 
  879. //                 // Recast.
  880. //                 pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  881. // 
  882. //                 // Get PCL.
  883. //                 pTransferPacketPCL =
  884. //                     LynxFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLTransferPacket);
  885. // 
  886. //                 // Update buffer size of transfer PCL.
  887. //                 pclControl = EndianSwap32Bit (pTransferPacketPCL->buffer[0].control);
  888. //                 pclControl = (pclControl & ~kLynxDMA_TransferCount) |
  889. //                              ((pDCLTransferPacket->size) << kLynxDMA_TransferCountPhase);
  890. //                 pTransferPacketPCL->buffer[0].control = EndianSwap32Bit (pclControl);
  891. // 
  892. //                 // Update buffer address of transfer PCL.
  893. //                 // WARNING WARNING this won't work with VM on - this is a logical address
  894. //                 pTransferPacketPCL->buffer[0].address =
  895. //                     (UInt32 *) EndianSwap32Bit ((UInt32) pDCLTransferPacket->buffer);
  896.  
  897.             default :
  898.                 break;
  899.         }
  900.     }
  901.  
  902.     return status;
  903. }
  904.  
  905.  
  906. ////////////////////////////////////////////////////////////////////////////////
  907. //
  908. // PrepareDCLProgramMemory
  909. //
  910. // Prepare all buffers used within a DCL program for physical I/O,
  911. // and determine the physical addresses.  dclList is the entire program.
  912. //
  913.  
  914. static OSStatus PrepareDCLProgramMemory(
  915.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData,
  916.     DCLCommandPtr                dclList,
  917.     UInt32                        dclListLength)
  918. {
  919.     DCLCommandPtr                pDCL;
  920.     DCLTransferPacketPtr        pDCLTransferPacket;
  921.     IOPreparationTable            *ioPrep;
  922.     PhysicalAddress                *physAddrs;                // should be PhysicalMappingTablePtr
  923.     AddressRangeTablePtr        rangeTable;
  924.     UInt32                        pageSize, pageShift;
  925.     UInt32                        pageCount, bufferCount;
  926.     AbsoluteTime                timeNow;
  927.     OSStatus                    status = noErr;
  928.     
  929.     ioPrep = &pDCLCompilerEngineData->ioPrep;
  930.     pageSize = pDCLCompilerEngineData->pFWIMData->pageSize;
  931.     pageShift = pDCLCompilerEngineData->pFWIMData->pageShift;
  932.     
  933.     // This is gross too.  Make sure we don't use stale data in lookups.
  934.     timeNow = UpTime();
  935.     pDCLCompilerEngineData->engineGeneration = AbsoluteToDuration(timeNow);
  936.     
  937.     // We will need to allocate a page table.  We don't know how big it needs
  938.     // to be, but we can wait until just before we PrepareMemoryForIO to do
  939.     // the allocation (by then we'll know)
  940.     
  941.     // We need to allocate a range/length table.  We fill that in before we
  942.     // call PrepareMemoryForIO, and it has to be linear, so we have to allocate
  943.     // it all at once.  We need one entry for each buffer in the program.
  944.     // That's why we take a parameter indicating the program length.
  945.     // Note if we ever allow scatter/gather buffers in a DCL program, this
  946.     // will have to change.
  947.     
  948.     // We assumed (in CompileDCLProgram) that each DCL contained a buffer.
  949.     // Some of them are branches, etc, so an optimization would be to count more
  950.     // precisely and save a little memory.
  951.     
  952.     // Allocate space for rangeTable
  953.     if (status == noErr)
  954.     {        
  955.         rangeTable = (AddressRangeTablePtr)
  956.             PoolAllocateResident(dclListLength * sizeof(AddressRange), false);
  957.         if (!rangeTable)
  958.             status = memFullErr;
  959.         
  960.         ioPrep->rangeInfo.multipleRanges.entryCount = 0;
  961.         // move this below, use local copy
  962.         ioPrep->rangeInfo.multipleRanges.rangeTable = rangeTable;
  963.     }    
  964.  
  965.     // Gather information about buffers/pointers
  966.     if (status == noErr)
  967.     {
  968.         pDCL = dclList;
  969.         bufferCount = 0;        // shadow of ioPrep->rangeInfo.multipleRanges.entryCount
  970.         pageCount = 0;            // count page table size we will need to allocate
  971.         
  972.         while (pDCL != nil)
  973.         {
  974.             switch (pDCL->opcode & ~kFWDCLOpFlagMask)
  975.             {
  976.                 case kDCLReceivePacketStartOp :
  977.                 case kDCLReceivePacketOp :
  978.                 case kDCLSendPacketStartOp :
  979.                 case kDCLSendPacketWithHeaderStartOp :
  980.                 case kDCLSendPacketOp :
  981.  
  982.                     pDCLTransferPacket = (DCLTransferPacketPtr) pDCL;
  983.                     rangeTable[bufferCount].base = (void *) pDCLTransferPacket->buffer;
  984.                     rangeTable[bufferCount].length = pDCLTransferPacket->size;
  985.                     bufferCount++;
  986.                     
  987.                     // buffer + size - 1 is addr of last byte in buffer.
  988.                     // shift that right by pageShift to get page index of end.
  989.                     // subtract first page index and add one to get total page count.
  990.                     
  991.                     pageCount += // (last page - first page) + 1
  992.                         ((((((UInt32) (pDCLTransferPacket->buffer)) + pDCLTransferPacket->size) - 1) >> pageShift) -
  993.                             (((UInt32) (pDCLTransferPacket->buffer)) >> pageShift) + 1);
  994.                     break;
  995.                     
  996.                 default : //No buffer or pointer - nothing to do
  997.                     break;
  998.             }
  999.  
  1000.             pDCL = pDCL->pNextDCLCommand;
  1001.         }
  1002.     }
  1003.  
  1004.     // Allocate space for page table
  1005.     if (status == noErr)
  1006.     {
  1007.         physAddrs = PoolAllocateResident(pageCount * sizeof(PhysicalAddress), false);
  1008.         if (!physAddrs)
  1009.         {
  1010.             status = memFullErr;
  1011.             PoolDeallocate((Ptr) rangeTable);
  1012.         }
  1013.     }
  1014.     
  1015.     // Prepare memory for I/O
  1016.     if (status == noErr)
  1017.     {
  1018.         ioPrep->options = kIOMultipleRanges | kIOLogicalRanges |
  1019.                           kIOIsInput | kIOIsOutput;
  1020.         ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  1021.         ioPrep->granularity = 0;                                // do it all now
  1022.         ioPrep->firstPrepared = 0;
  1023.         ioPrep->mappingEntryCount = pageCount;                    // we counted exactly
  1024.         ioPrep->logicalMapping = 0;
  1025.         ioPrep->physicalMapping = physAddrs;                    // return list of phys addrs
  1026.         ioPrep->rangeInfo.multipleRanges.entryCount = bufferCount;
  1027.  
  1028.         // CheckpointIO is in ReleaseIsochPort
  1029.         status = PrepareMemoryForIO(ioPrep);
  1030.         if (status != noErr)
  1031.         {
  1032.             ioPrep->mappingEntryCount = -1;                        // prevents CheckpointIO, kind of a hack
  1033.             PoolDeallocate((Ptr) rangeTable);
  1034.             PoolDeallocate((Ptr) physAddrs);
  1035.         }
  1036.     }
  1037.     
  1038.     return status;
  1039. }
  1040.  
  1041.  
  1042. ////////////////////////////////////////////////////////////////////////////////
  1043. //
  1044. // AllocateDMA
  1045. //
  1046. // Allocate a block of DMA descriptors.
  1047. //
  1048.  
  1049. static OSStatus    AllocateDMA(
  1050.     DMABuildStatePtr            pDMABuildState,
  1051.     DMADescriptorPtr            *ppDMA,
  1052.     PhysicalAddress                *ppDMAPhys,
  1053.     UInt32                        count)
  1054.  
  1055. {
  1056.     DMAPoolDataPtr                pDMAPoolData;
  1057.     DMADescriptorPtr            pDMA,
  1058.                                 dmaPool;
  1059.     UInt32                        dmaPoolPhys;
  1060.     UInt32                        nextFreeDMA;
  1061.     UInt32                        descriptorCount;
  1062.     IOPreparationTable            *ioPrep;
  1063.     UInt32                        pageSize;
  1064.     Ptr                            p;
  1065.     OSStatus                    status = noErr;
  1066.     
  1067.     // Get pool data record.
  1068.     pDMAPoolData = pDMABuildState->pDMAPoolDataList;
  1069.     
  1070.     // Get DMA pool and next free DMA index.
  1071.     if (pDMAPoolData != nil)
  1072.     {
  1073.         dmaPool = pDMAPoolData->DMAPoolBase;
  1074.         dmaPoolPhys = pDMAPoolData->DMAPoolBasePhys;
  1075.         nextFreeDMA = pDMAPoolData->nextFreeDMA;
  1076.     }
  1077.     else
  1078.     {
  1079.         dmaPool = nil;
  1080.     }
  1081.     
  1082.     // Allocate new pool if current pool is exhausted.
  1083.     // This pool needs to be aligned to the descriptor size for the compilation logic
  1084.     // to work properly.  Pool size can exceed one phys page as long as we have an
  1085.     // allocator which gives us contiguous pages.
  1086.     //
  1087.     // JKL *** Allocate a page. Use how ever many descriptors are available in a page
  1088.     // size less the size of the DMAPoolData record.
  1089.     
  1090.  
  1091.     if ((dmaPool == nil) || ((nextFreeDMA + count) > pDMAPoolData->DMAPoolCount))
  1092.     {
  1093.         pageSize = pDMABuildState->pFWIMData->pageSize;
  1094.         p = MemAllocatePhysicallyContiguous(pageSize, true);
  1095.         if (p != nil)
  1096.         {
  1097.             // Assign DMAPoolData record to end of DMA descriptor memory
  1098.             descriptorCount = (pageSize - sizeof(DMAPoolData)) / sizeof(DMADescriptor);
  1099.             descriptorCount -= 2;        // subtract two to alleviate any rounding problems and leave room for isochRxDummyQuadPhys
  1100.             pDMAPoolData = (DMAPoolDataPtr) (p + (descriptorCount * sizeof(DMADescriptor)));
  1101.             pDMAPoolData->DMAPoolCount = descriptorCount;
  1102.             
  1103.             // Prepare for IO and get physical address
  1104.             ioPrep = &pDMAPoolData->ioPrep;
  1105.             ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  1106.             ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  1107.             ioPrep->granularity = 0;                                // do it all now
  1108.             ioPrep->firstPrepared = 0;
  1109.             ioPrep->mappingEntryCount = 1;                            // # of pages we will use
  1110.             ioPrep->logicalMapping = 0;
  1111.             ioPrep->physicalMapping = pDMAPoolData->physAddrs;        // return list of phys addrs
  1112.             ioPrep->rangeInfo.range.base = p;
  1113.             ioPrep->rangeInfo.range.length = pageSize;
  1114.             
  1115.             // The CheckpointIO is in DeallocateDMAPools
  1116.             status = PrepareMemoryForIO(ioPrep);
  1117. //             if (status != noErr)
  1118. //             {
  1119. //                 sprintf (debugStr, "PCL Pool PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  1120. //                          (long) status,
  1121. //                          (long) ioPrep->rangeInfo.range.base,
  1122. //                          (long) pOHCIPCLPoolData->physAddrs[0],
  1123. //                          (long) ioPrep->rangeInfo.range.length);
  1124. //                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1125. //             }
  1126.  
  1127.             pDMAPoolData->pNextDMAPoolData = pDMABuildState->pDMAPoolDataList;
  1128.             pDMABuildState->pDMAPoolDataList = pDMAPoolData;
  1129.             pDMAPoolData->DMAPoolBase = (DMADescriptorPtr) p;
  1130.             pDMAPoolData->DMAPoolBasePhys = (UInt32) pDMAPoolData->physAddrs[0];
  1131.             
  1132.             nextFreeDMA = 0;
  1133.             dmaPool = pDMAPoolData->DMAPoolBase;
  1134.             dmaPoolPhys = pDMAPoolData->DMAPoolBasePhys;
  1135.         }
  1136.         else
  1137.         {
  1138.             status = memFullErr;
  1139.         }
  1140.     }
  1141.     
  1142.     // JKL *** Hack Alert, take a left over quad from the allocation and assign it to
  1143.     // pFWIMData->isochRxDummyQuadPhys for use in isoch receive of the first timeStamp quad.
  1144.     if ((pDMABuildState->isochRxDummyQuadPhys == 0) && (status == noErr))
  1145.     {
  1146.         pDMABuildState->isochRxDummyQuadPhys =
  1147.             dmaPoolPhys + (descriptorCount * sizeof(DMADescriptor)) + sizeof(DMAPoolData);
  1148.     }
  1149.     
  1150.     // Allocate descriptor from pool.
  1151.     if (status == noErr)
  1152.     {
  1153.         pDMA = &dmaPool[nextFreeDMA];
  1154.         nextFreeDMA += count;
  1155.         pDMAPoolData->nextFreeDMA = nextFreeDMA;
  1156.     }
  1157.  
  1158.     // Return results.
  1159.     if (status == noErr)
  1160.     {
  1161.         *ppDMA = pDMA;
  1162.         *ppDMAPhys = (PhysicalAddress) (dmaPoolPhys + (((UInt32) pDMA) - ((UInt32) dmaPool)));
  1163.     }
  1164.     else
  1165.     {
  1166.         *ppDMA = nil;
  1167.         *ppDMAPhys = nil;
  1168.     }
  1169.     return status;
  1170. }
  1171.  
  1172.  
  1173. ////////////////////////////////////////////////////////////////////////////////
  1174. //
  1175. // DCLCompilerNotification
  1176. //
  1177. // Handle update notifications for the DCL to DMA program compiler.
  1178. //
  1179.  
  1180. static OSStatus DCLCompilerNotification(
  1181.     DCLProgramID                dclProgramID,
  1182.     UInt32                        notificationType,
  1183.     DCLCommandPtr                *dclCommandList,
  1184.     UInt32                        numDCLCommands)
  1185. {
  1186.     OSStatus                    status = noErr;
  1187.  
  1188.     switch (notificationType)
  1189.     {
  1190.         case kFWDCLUpdateNotification:
  1191.             status = DCLCompilerUpdateNotification(dclProgramID,
  1192.                                                    dclCommandList,
  1193.                                                    numDCLCommands);
  1194.             break;
  1195.  
  1196.         case kFWDCLModifyNotification:
  1197.             status = DCLCompilerModifyNotification(dclProgramID,
  1198.                                                    dclCommandList,
  1199.                                                    numDCLCommands);
  1200.             break;
  1201.  
  1202.         default:
  1203.             status = paramErr;
  1204.             break;
  1205.     }
  1206.  
  1207.     return status;
  1208. }
  1209.  
  1210.  
  1211. ////////////////////////////////////////////////////////////////////////////////
  1212. //
  1213. // DCLCompilerUpdateNotification
  1214. //
  1215. // Handle update notifications for the DCL to DMA compiler.  This will
  1216. // do any neccessary CheckPointIOs and update any DCL status fields.
  1217. //zzz do the right stuff in here
  1218. //
  1219.  
  1220. static OSStatus DCLCompilerUpdateNotification(
  1221.     DCLProgramID                dclProgramID,
  1222.     DCLCommandPtr                *dclCommandList,
  1223.     UInt32                        numDCLCommands)
  1224. {
  1225.     DCLCommandPtr                pDCLCommand;
  1226.     UInt32                        dclCommandNum;
  1227.     OSStatus                    status = noErr;
  1228.  
  1229.     for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
  1230.     {
  1231.         pDCLCommand = dclCommandList[dclCommandNum];
  1232.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  1233.         {
  1234. //    JKL *** This is already handled in the IsochTransmitDeferredTask
  1235. //             case kDCLTimeStampOp :
  1236. //                 UpdateDCLTimeStamp(pDCLCommand);
  1237. //                 break;
  1238.  
  1239.             case kDCLReceivePacketStartOp :
  1240.                 UpdateDCLReceivePacketStart((DCLTransferPacketPtr) pDCLCommand);
  1241.                 break;
  1242.  
  1243.             // I think we might want to CheckpointIO () on the live buffers, etc...?
  1244.             default :
  1245.                 break;
  1246.         }
  1247.     }
  1248.  
  1249.     return status;
  1250. }
  1251.  
  1252.  
  1253. ////////////////////////////////////////////////////////////////////////////////
  1254. //
  1255. // StartTalkingDCLProgram
  1256. //
  1257. // Start running the given DCL program.
  1258. //
  1259.  
  1260. static OSStatus StartTalkingDCLProgram(
  1261.     DCLProgramID                dclProgramID)
  1262. {
  1263.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData;
  1264.     FWIMDataPtr                    pFWIMData;
  1265.     OHCIRegistersPtr            pOHCIRegs;
  1266.     OSStatus                    status = noErr;
  1267.  
  1268.     // Get our engine data and FWIM data.
  1269.     status = FWGetDCLProgramEngineData(dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
  1270.     if (status == noErr)
  1271.         pFWIMData = pDCLCompilerEngineData->pFWIMData;
  1272.  
  1273.     // Get base address of OHCI registers.
  1274.     if (status == noErr)
  1275.         pOHCIRegs = pFWIMData->pOHCIRegisters;
  1276.  
  1277.     // Start the DMA engine.
  1278.     if (status == noErr)
  1279.     {
  1280.         // Load physical address of DMA
  1281.         // kind of a hack, physical DMA value includes Z value
  1282.         pOHCIRegs->isochTxContext[kITContext0].commandPtr =
  1283.             EndianSwapImm32Bit((UInt32) pDCLCompilerEngineData->pStartDMA);
  1284.         SynchronizeIO ();
  1285.  
  1286.         // Setup cycle start.
  1287.         if (pDCLCompilerEngineData->startEvent == kFWDCLCycleEvent)
  1288.         {
  1289.             pOHCIRegs->isochTxContext[kITContext0].controlSet =
  1290.                 EndianSwapImm32Bit(kITDMACycleMatchEnable | 
  1291.                 (pDCLCompilerEngineData->startEventState << kITDMACycleMatchPhase) & kITDMACycleMatch);
  1292.             SynchronizeIO();
  1293.         }
  1294.  
  1295.         // start the DMA
  1296.         pOHCIRegs->isochTxContext[kITContext0].controlSet = EndianSwapImm32Bit(kDMARun);
  1297.         SynchronizeIO ();
  1298.     }
  1299.  
  1300.     return status;
  1301. }
  1302.  
  1303.  
  1304. ////////////////////////////////////////////////////////////////////////////////
  1305. //
  1306. // StopTalkingDCLProgram
  1307. //
  1308. // Stop running the given DCL program.
  1309. //
  1310.  
  1311. static OSStatus StopTalkingDCLProgram(
  1312.     DCLProgramID                dclProgramID)
  1313. {
  1314.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData;
  1315.     FWIMDataPtr                    pFWIMData;
  1316.     OHCIRegistersPtr            pOHCIRegs;
  1317.     OSStatus                    status = noErr;
  1318.  
  1319.     // Get our engine data and FWIM data.
  1320.     status = FWGetDCLProgramEngineData
  1321.                 (dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
  1322.     if (status == noErr)
  1323.         pFWIMData = pDCLCompilerEngineData->pFWIMData;
  1324.  
  1325.     // Get base address of OHCI registers.
  1326.     if (status == noErr)
  1327.         pOHCIRegs = pFWIMData->pOHCIRegisters;
  1328.  
  1329.     // Stop the DMA engine.
  1330.     if (status == noErr)
  1331.     {
  1332.         // Stop the DMA.
  1333.         // zzzCould be more graceful, not send partial packet?
  1334.         pOHCIRegs->isochTxContext[kITContext0].controlClear = 0;
  1335.         SynchronizeIO ();
  1336.     }
  1337.  
  1338.     return status;
  1339. }
  1340.  
  1341.  
  1342. ////////////////////////////////////////////////////////////////////////////////
  1343. //
  1344. // ReleaseDCLProgram
  1345. //
  1346. // Release the resources allocated for the given DCL program.
  1347. //
  1348.  
  1349. static OSStatus ReleaseDCLProgram(
  1350.     DCLProgramID                dclProgramID)
  1351. {
  1352.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData;
  1353.     FWIMDataPtr                    pFWIMData;
  1354.     OSStatus                    status = noErr;
  1355.  
  1356.     // Get our engine data and FWIM data.
  1357.     status = FWGetDCLProgramEngineData
  1358.                 (dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
  1359.     if (status == noErr)
  1360.         pFWIMData = pDCLCompilerEngineData->pFWIMData;
  1361.  
  1362.     if (status == noErr)
  1363.     {
  1364.         // Deallocate DMA pools.
  1365.         if (pDCLCompilerEngineData->pDMAPoolDataList != nil)
  1366.         {
  1367.             DeallocateDMAPools(pDCLCompilerEngineData->pDMAPoolDataList);
  1368.         }
  1369.         
  1370.         // Release all VM resources
  1371.         // Kind of a hack - we set this to -1 if the PrepareMemoryForIO failed:
  1372.         if (pDCLCompilerEngineData->ioPrep.mappingEntryCount != -1)
  1373.         {
  1374.             status = CheckpointIO (pDCLCompilerEngineData->ioPrep.preparationID, kNilOptions);
  1375. //             if (status != noErr)
  1376. //             {
  1377. //                 sprintf (debugStr, "DCL data CheckpointIO status %ld",
  1378. //                          (long) status);
  1379. //                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1380. //             }
  1381.             PoolDeallocate ((Ptr) pDCLCompilerEngineData->ioPrep.rangeInfo.multipleRanges.rangeTable);
  1382.             PoolDeallocate ((Ptr) pDCLCompilerEngineData->ioPrep.physicalMapping);
  1383.         }
  1384.         
  1385.         // Deallocate compiler data list for DCLs
  1386.         if (pDCLCompilerEngineData->pDCLCompilerDCLData != nil)
  1387.             PoolDeallocate ((Ptr) pDCLCompilerEngineData->pDCLCompilerDCLData);
  1388.  
  1389.         // Deallocate engine data.
  1390.         PoolDeallocate ((Ptr) pDCLCompilerEngineData);
  1391.     }
  1392.     
  1393.     return status;
  1394. }
  1395.  
  1396.  
  1397. ////////////////////////////////////////////////////////////////////////////////
  1398. //
  1399. // ReleaseIsochPort
  1400. //
  1401. // Release resources allocated for the given isochronous channel.
  1402. //
  1403.  
  1404. static OSStatus ReleaseIsochPort(
  1405.     FWIMDataPtr                    pFWIMData,
  1406.     IsochPortDataPtr            pIsochPortData)
  1407. {
  1408.     DCLCompilerEngineDataPtr     pDCLCompilerEngineData = nil;
  1409.     OSStatus                    status = noErr;
  1410.  
  1411.     // Release DCL resources.
  1412.     if (pIsochPortData->originalDCLProgramID != (DCLProgramID) kInvalidDCLProgramID)
  1413.         status = FWReleaseDCLProgram(pIsochPortData->originalDCLProgramID);
  1414.     
  1415.     // Deallocate isoch port data record.
  1416.     PoolDeallocate((Ptr) pIsochPortData);
  1417.     
  1418.     return status;
  1419. }
  1420.  
  1421.  
  1422. ////////////////////////////////////////////////////////////////////////////////
  1423. //
  1424. // StartListeningDCLProgram
  1425. //
  1426. // Start running the given DCL program.
  1427. //
  1428.  
  1429. static OSStatus StartListeningDCLProgram(
  1430.     DCLProgramID                dclProgramID)
  1431. {
  1432.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData;
  1433.     FWIMDataPtr                    pFWIMData;
  1434.     OHCIRegistersPtr            pOHCIRegs;
  1435.     OSStatus                    status = noErr;
  1436.  
  1437.     // Get our engine data and FWIM data.
  1438.     status = FWGetDCLProgramEngineData(dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
  1439.     if (status == noErr)
  1440.         pFWIMData = pDCLCompilerEngineData->pFWIMData;
  1441.  
  1442.     // Get base address of OHCI registers.
  1443.     if (status == noErr)
  1444.         pOHCIRegs = pFWIMData->pOHCIRegisters;
  1445.  
  1446.     // Start the DMA engine.
  1447.     if (status == noErr)
  1448.     {
  1449.         // Load physical address of starting DMA,
  1450.         // Kind of a hack, already added Z value to pStartDMA physical address
  1451.         pOHCIRegs->isochRxContext[kIRContext0].commandPtr =
  1452.             EndianSwapImm32Bit((UInt32) pDCLCompilerEngineData->pStartDMA);
  1453.         SynchronizeIO ();
  1454.  
  1455.         // Setup cycle start.
  1456.         if (pDCLCompilerEngineData->startEvent == kFWDCLCycleEvent)
  1457.         {
  1458.             pOHCIRegs->isochRxContext[kIRContext0].controlSet = EndianSwapImm32Bit(kIRDMACycleMatchEnable);
  1459.             pOHCIRegs->isochRxContext[kIRContext0].match =
  1460.                 EndianSwapImm32Bit((pDCLCompilerEngineData->startEventState << kIRDMACycleMatchPhase) & kIRDMACycleMatch);
  1461.             SynchronizeIO();
  1462.         }
  1463.  
  1464.         // start the DMA
  1465.         pOHCIRegs->isochRxContext[kIRContext0].controlSet = EndianSwapImm32Bit(kDMARun);
  1466.         SynchronizeIO ();
  1467.     }
  1468.  
  1469.     return status;
  1470. }
  1471.  
  1472.  
  1473. ////////////////////////////////////////////////////////////////////////////////
  1474. //
  1475. // StopListeningDCLProgram
  1476. //
  1477. // Stop running the given DCL program.
  1478. //
  1479.  
  1480. static OSStatus StopListeningDCLProgram(
  1481.     DCLProgramID                dclProgramID)
  1482. {
  1483.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData;
  1484.     FWIMDataPtr                    pFWIMData;
  1485.     OHCIRegistersPtr            pOHCIRegs;
  1486.     OSStatus                    status = noErr;
  1487.  
  1488.     // Get our engine data and FWIM data.
  1489.     status = FWGetDCLProgramEngineData(dclProgramID, (UInt32 *) &pDCLCompilerEngineData);
  1490.     if (status == noErr)
  1491.         pFWIMData = pDCLCompilerEngineData->pFWIMData;
  1492.  
  1493.     // Get base address of OHCI registers.
  1494.     if (status == noErr)
  1495.         pOHCIRegs = pFWIMData->pOHCIRegisters;
  1496.  
  1497.     // Stop the DMA engine.
  1498.     if (status == noErr)
  1499.     {
  1500.         // Stop the DMA - zzz could be more graceful, not stop mid-packet.
  1501.         //zzz need way to bit bucket any remaining packets in FIFO
  1502.         pOHCIRegs->isochRxContext[kIRContext0].controlClear = EndianSwapImm32Bit(kDMARun);
  1503.         SynchronizeIO ();
  1504.     }
  1505.  
  1506.     return status;
  1507. }
  1508.  
  1509.  
  1510. ////////////////////////////////////////////////////////////////////////////////
  1511. //
  1512. // AddDCL
  1513. //
  1514. // Add the packet DCL command to the DMA program.
  1515. //
  1516. // The DMA program is built in two passes, the first creates all of the
  1517. // packet DMA descriptors, handles DCL's that generate interrupts such
  1518. // as TimeStamp, CallProc, and Update, and sets up some of the jump/label
  1519. // information. The second pass completes the labels and jumps.
  1520. //
  1521. // JKL *** There may be some problems handling updates and dynamic values with this.
  1522. //
  1523.  
  1524. static OSStatus AddDCL(
  1525.     DMABuildStatePtr            pDMABuildState,
  1526.     DCLCommandPtr                pDCLCommand,
  1527.     UInt32                        speed)
  1528. {
  1529.     UInt32                        opcode;
  1530.     OSStatus                    status = noErr;
  1531.  
  1532.     // Dispatch off of opcode.
  1533.     opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  1534.     switch (opcode)
  1535.     {
  1536.         case kDCLReceivePacketStartOp:
  1537.             status = AddReceivePacketStartDCL(pDMABuildState, pDCLCommand);
  1538.             break;
  1539.             
  1540.         case kDCLReceivePacketOp:
  1541.             status = AddReceivePacketDCL(pDMABuildState, pDCLCommand);
  1542.             break;
  1543.             
  1544.         case kDCLSendPacketStartOp:
  1545.             status = AddSendPacketStartDCL(pDMABuildState, pDCLCommand, speed);
  1546.             break;
  1547.             
  1548.         case kDCLSendPacketWithHeaderStartOp:
  1549.             status = AddSendPacketWithHeaderStartDCL(pDMABuildState, pDCLCommand, speed);
  1550.             break;
  1551.             
  1552.         case kDCLSendPacketOp:
  1553.             status = AddSendPacketDCL(pDMABuildState, pDCLCommand);
  1554.             break;
  1555.  
  1556.          case kDCLCallProcOp:
  1557.              status = AddCallProcDCL(pDMABuildState, pDCLCommand);
  1558.              break;
  1559.  
  1560.          case kDCLSetTagSyncBitsOp:
  1561.              status = AddSetTagSyncBitsDCL(pDMABuildState, pDCLCommand);
  1562.              break;
  1563.  
  1564.          case kDCLUpdateDCLListOp:
  1565.              status = AddUpdateDCLListDCL(pDMABuildState, pDCLCommand);
  1566.              break;
  1567.  
  1568.          case kDCLTimeStampOp:
  1569.              status = AddTimeStampDCL(pDMABuildState, pDCLCommand);
  1570.              break;
  1571.  
  1572.          case kDCLJumpOp:
  1573.              status = AddJumpAddress(pDMABuildState, pDCLCommand);
  1574.              break;
  1575.  
  1576.         default:
  1577.             break;
  1578.     }    
  1579.     return status;
  1580. }
  1581.  
  1582.  
  1583. ////////////////////////////////////////////////////////////////////////////////
  1584. //
  1585. // DeallocateDMAPools
  1586. //
  1587. // Deallocate the given list of DMA descriptor pools.
  1588. //
  1589.  
  1590. static void DeallocateDMAPools(
  1591.     DMAPoolDataPtr                pDMAPoolDataList)
  1592. {
  1593.     DMAPoolDataPtr                pDMAPoolData,
  1594.                                 pNextDMAPoolData;
  1595.     OSStatus                    status = noErr;
  1596.  
  1597.     // Deallocate each pool in list.
  1598.     pDMAPoolData = pDMAPoolDataList;
  1599.     while (pDMAPoolData != nil)
  1600.     {
  1601.         pNextDMAPoolData = pDMAPoolData->pNextDMAPoolData;
  1602.         status = CheckpointIO(pDMAPoolData->ioPrep.preparationID, kNilOptions);
  1603. //         if (status != noErr)
  1604. //         {
  1605. //             sprintf (debugStr, "PCL Pool CheckpointIO status %ld    ID was %08lx",
  1606. //                      (long) status,
  1607. //                      (long) pNextOHCIPCLPoolData->ioPrep.preparationID);
  1608. //             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1609. //         }
  1610.  
  1611.         status = MemDeallocatePhysicallyContiguous(pDMAPoolData->DMAPoolBase);
  1612. //         if (status != noErr)
  1613. //             FWDebugStr ((ConstStr255Param) "\p Dealloc error!!");
  1614.  
  1615.         pDMAPoolData = pNextDMAPoolData;
  1616.     }
  1617. }
  1618.  
  1619.  
  1620. ////////////////////////////////////////////////////////////////////////////////
  1621. //
  1622. // AddReceivePacketStartDCL
  1623. //
  1624. // Add a receive packet start DCL.
  1625. //
  1626.  
  1627. static OSStatus AddReceivePacketStartDCL (
  1628.     DMABuildStatePtr            pDMABuildState,
  1629.     DCLCommandPtr                pDCLCommand)
  1630. {
  1631.     FWIMDataPtr                    pFWIMData;
  1632.     DCLTransferPacketPtr        pDCLTransferPacket;
  1633.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  1634.     DCLCompilerDCLDataPtr        pInterruptDCLCompilerDCLData;
  1635.     DMADescriptorPtr            pDoDMA, pDMA;
  1636.     PhysicalAddress                pDMAPhys;
  1637.     PhysicalAddress                physTable[7];        // 7 is max, we use one for dummy header quad
  1638.     UInt32                        sizeTable[7];
  1639.     UInt32                        packetSize, packetPageCount;
  1640.     UInt32                        pageCount, pageIndex, pageSize;
  1641.     UInt32                        startingInterruptCount;
  1642.     OSStatus                    status = noErr;
  1643.     Boolean                        needsInterrupt = false;
  1644.  
  1645.     // Recast DCL command.
  1646.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  1647.     pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
  1648.     pFWIMData = pDMABuildState->pFWIMData;
  1649.     
  1650.     // Scan for any ReceivePacketOp DCLs that follow this ReceivePacketStartOp DCL.
  1651.     // They will all combine with this one to send a single packet. Find out
  1652.     // all of the physical addresses and data sizes, including descriptor count.
  1653.  
  1654.     packetSize = 0;
  1655.     packetPageCount = 0;
  1656.     pageSize = pFWIMData->pageSize;
  1657.  
  1658.     // Get physical addresses.
  1659.     do
  1660.     {
  1661.         packetSize += pDCLTransferPacket->size;
  1662.         pageCount = DataMapToPhysical(pDMABuildState->pDCLCompilerEngineData,
  1663.                                       pDCLTransferPacket->buffer,
  1664.                                       pDCLTransferPacket->size,
  1665.                                       &physTable[packetPageCount]);
  1666.  
  1667.         // determine reqCount for preliminary page(s)
  1668.         for (pageIndex = 0; pageIndex < (pageCount - 1); pageIndex++, packetPageCount++) 
  1669.         {
  1670.             if (pageIndex == 0)
  1671.                 sizeTable[packetPageCount] = pageSize - ((UInt32) pDCLTransferPacket->buffer & (pageSize - 1));
  1672.             else
  1673.                 sizeTable[packetPageCount] = pageSize;
  1674.         }
  1675.  
  1676.         // determine reqCount for last page, could also be first page
  1677.         if (pageCount == 1)
  1678.             sizeTable[packetPageCount] = pDCLTransferPacket->size;
  1679.         else
  1680.             sizeTable[packetPageCount] = ((UInt32) pDCLTransferPacket->buffer + pDCLTransferPacket->size) & (pageSize - 1);
  1681.  
  1682.         packetPageCount++;
  1683.         
  1684.         pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
  1685.  
  1686.         if (pDCLTransferPacket != nil)
  1687.         {
  1688.             if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) != kDCLSendPacketOp)
  1689.             {
  1690.                 // look ahead to see if packet receipt needs to trigger interrupt
  1691.                 // save interrupt count since it gets updated in this routine
  1692.                 startingInterruptCount = pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum];
  1693.                 needsInterrupt = AddReceiveDCLInterrupt((DCLCommandPtr) pDCLTransferPacket, pFWIMData, pDMABuildState->dmaPortNum);
  1694.                 
  1695.                 pDCLTransferPacket = nil;                
  1696.             }
  1697.         }
  1698.  
  1699.     } while (pDCLTransferPacket != nil);
  1700.     
  1701.     if (packetPageCount > 7)
  1702.     {
  1703.         status = -1;
  1704.         FWDebugStr("\pAddSendPacketStartDCL, too many descriptors");
  1705.     }
  1706.     
  1707.     packetPageCount++;
  1708.     packetSize += 4;
  1709.     
  1710.     // Allocate contiguous descriptors
  1711.     if (status == noErr)
  1712.     {
  1713.         status = AllocateDMA(pDMABuildState, &pDMA, &pDMAPhys, packetPageCount);
  1714.         pDoDMA = pDMA;
  1715.     }
  1716.  
  1717.     // fill in descriptor for first dummy quad
  1718.     if (status == noErr)
  1719.     {        
  1720.         // Set up INPUT_MORE descriptor.
  1721.         // JKL *** What about wait control for sync field
  1722.         pDoDMA->descriptorField[0] = EndianSwapImm32Bit(kInputMoreCmd << kDMACommandPhase | 4);
  1723.         pDoDMA->descriptorField[1] = EndianSwapImm32Bit(pDMABuildState->isochRxDummyQuadPhys);
  1724.         pDoDMA->descriptorField[2] = 0;
  1725.         pDoDMA->descriptorField[3] = EndianSwapImm32Bit(4);
  1726.         pDoDMA++;
  1727.     }
  1728.     
  1729.     // fill in DMA descriptor block
  1730.     if (status == noErr)
  1731.     {        
  1732.         // For buffers that take up more than a page, set up INPUT_MORE
  1733.         // descriptors for the prelimary pages
  1734.         for (pageIndex = 0; pageIndex < (packetPageCount - 2); pageIndex++) 
  1735.         {
  1736.             // Set up INPUT_MORE descriptor.
  1737.             pDoDMA->descriptorField[0] = EndianSwapImm32Bit(kInputMoreCmd << kDMACommandPhase | sizeTable[pageIndex]);
  1738.             pDoDMA->descriptorField[1] = EndianSwapImm32Bit((UInt32) physTable[pageIndex]);
  1739.             pDoDMA->descriptorField[2] = 0;
  1740.             pDoDMA->descriptorField[3] = EndianSwapImm32Bit(sizeTable[pageIndex]);
  1741.             pDoDMA++;
  1742.         }
  1743.     
  1744.         // Set up INPUT_LAST descriptor.
  1745.         pDoDMA->descriptorField[0] = EndianSwapImm32Bit(
  1746.                                         kInputLastCmd  << kDMACommandPhase |    // packet-per-buffer mode
  1747.                                         kBranchAlways << kDMABranchPhase |        // branch to next descriptor
  1748.                                         sizeTable[pageIndex]);                    // rest of packet buffer
  1749.         if (needsInterrupt)
  1750.         {
  1751.             // set interrupt and update status bits
  1752.             pDoDMA->descriptorField[0] |= EndianSwapImm32Bit(kInterruptAlways << kDMAInterruptPhase | kDMAInputStatus);
  1753.  
  1754.             // save xfer status descriptor field address in DCLInterrupt record
  1755.             // when interrupt comes in, check xfer status to see if descriptor completed, yuck
  1756.             while (startingInterruptCount < pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum])
  1757.             {
  1758.                 pDCLCommand = pFWIMData->pDCLInterruptList[pDMABuildState->dmaPortNum]
  1759.                                                           [startingInterruptCount].pDCLCommand;
  1760.                 pInterruptDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  1761.                 pInterruptDCLCompilerDCLData->pDMA = pDoDMA;
  1762.                 startingInterruptCount++;
  1763.             }
  1764.         }
  1765.         pDoDMA->descriptorField[1] = EndianSwapImm32Bit((UInt32) physTable[pageIndex]);
  1766.         pDoDMA->descriptorField[3] = EndianSwapImm32Bit(sizeTable[pageIndex]);     // set resCount to descriptor buffer size
  1767.     }
  1768.     
  1769.     // Link previous descriptor and add Z value.
  1770.     if ((status == noErr) && pDMABuildState->pLastBranch)
  1771.         *(pDMABuildState->pLastBranch) = EndianSwapImm32Bit((UInt32) pDMAPhys + packetPageCount);
  1772.  
  1773.     if (status == noErr)
  1774.         // The next descriptor's address goes here
  1775.         pDMABuildState->pLastBranch = (UInt32 *) &pDoDMA->descriptorField[2];
  1776.         
  1777.     // Initialize start DMA if not already set. Add Z value to address.
  1778.     if ((status == noErr) && (pDMABuildState->pDCLCompilerEngineData->pStartDMA == nil))
  1779.     {
  1780.         pDMABuildState->pDCLCompilerEngineData->pStartDMA = (UInt32) pDMAPhys + packetPageCount;
  1781.     }
  1782.     
  1783.     // Store results in DCL transfer packet record.
  1784.     //zzz should fill in CompilerDCLData for SendPacketOps we compiled.
  1785.     // but I don't think it ever gets used, unless we update buffers (NYI anyway)
  1786.     // Also store Z value in DMAPhys for use by label/jump. Mask 4 Z value bits
  1787.     // if address is ever used.
  1788.     if (status == noErr)
  1789.     {
  1790.         pDCLCompilerDCLData->pDMA = pDMA;
  1791.         pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) ((UInt32) pDMAPhys + packetPageCount);
  1792.     }
  1793.     else
  1794.     {
  1795.         pDCLCompilerDCLData->pDMA = nil;
  1796.         pDCLCompilerDCLData->pDMAPhys = nil;
  1797.     }
  1798.  
  1799.     return status;
  1800. }
  1801.  
  1802.  
  1803. ////////////////////////////////////////////////////////////////////////////////
  1804. //
  1805. // AddReceiveDCLInterrupt
  1806. //
  1807. // Look ahead at DCL commands to see if any interrupt opcodes follow a receive
  1808. // DCL. Add them to the interrupt list. The receive DCL processor will then
  1809. // add additional information to the new interrupt records.
  1810. //
  1811. static Boolean AddReceiveDCLInterrupt (
  1812.     DCLCommandPtr                pDCLCommand,
  1813.     FWIMDataPtr                    pFWIMData,
  1814.     UInt32                        portNum)
  1815. {
  1816.     UInt32                        opcode;
  1817.     DCLProgramInterruptPtr        pDCLInterrupt;
  1818.     Boolean                        foundInterruptDCL = false;
  1819.     
  1820.     while (pDCLCommand != nil)
  1821.     {
  1822.         opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  1823.         
  1824.         switch (opcode)
  1825.         {
  1826.             case kDCLCallProcOp:
  1827.             case kDCLUpdateDCLListOp:
  1828.             case kDCLTimeStampOp:
  1829.                 if (pFWIMData->numDCLInterrupts[portNum] < kNumDCLInterrupts)
  1830.                 {
  1831.                     foundInterruptDCL = true;
  1832.                     pDCLInterrupt = &pFWIMData->pDCLInterruptList[portNum][pFWIMData->numDCLInterrupts[portNum]];
  1833.                     pDCLInterrupt->pDCLCommand = pDCLCommand;
  1834.                     pDCLInterrupt->pendingInterrupt = false;
  1835.                     pFWIMData->numDCLInterrupts[portNum]++;
  1836.                     pDCLCommand = pDCLCommand->pNextDCLCommand;
  1837.                 }
  1838.                 else
  1839.                 {
  1840.                     pDCLCommand = nil;
  1841.                     FWDebugStr("\pAddReceiveDCLInterrupt, need more DCLProgramInterrupt records");
  1842.                 }
  1843.                 
  1844.                 break;
  1845.                 
  1846.             case kDCLLabelOp:
  1847.             case kDCLJumpOp:
  1848.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  1849.                 break;
  1850.  
  1851.             default:
  1852.                 pDCLCommand = nil;
  1853.         }
  1854.     }
  1855.  
  1856.     return foundInterruptDCL;
  1857. }
  1858.  
  1859.  
  1860. ////////////////////////////////////////////////////////////////////////////////
  1861. //
  1862. // DataMapToPhysical
  1863. //
  1864. // Look up physical addresses for buffers/pointers.
  1865. // Fills in the passed page table, returns page count (0 if not found)
  1866. //
  1867. static UInt32 DataMapToPhysical (
  1868.     DCLCompilerEngineDataPtr    pDCLCompilerEngineData,
  1869.     Ptr                            pBuffer,
  1870.     UInt32                        size,
  1871.     PhysicalMappingTablePtr        returnTable)
  1872. {
  1873.     UInt32                        pageCount = 0, lookCount = 0;
  1874.     UInt32                        pageShift;
  1875.     static UInt32                rangeLook = 0, pageLook = 0;
  1876.     static UInt32                cacheEngineGeneration = 0;
  1877.     IOPreparationTable            *ioPrep = &pDCLCompilerEngineData->ioPrep;
  1878.     AddressRangeTablePtr        try;
  1879.  
  1880.     pageShift = pDCLCompilerEngineData->pFWIMData->pageShift;
  1881.     
  1882.     // Look up phys addrs in our prepared table
  1883.     // Return in provided page table
  1884.     
  1885.     // Start lookup from last known point, if we build in order, lookup is fast
  1886.     // Strictly speaking, rangeLook and pageLook should be static to the
  1887.     // engine data, not the whole FWIM, but I don't think we can compile more
  1888.     // than one DCL program at a time anyway.
  1889.     //
  1890.     // Perhaps more importantly, they should be reset if we've rebuilt the ioPrep,
  1891.     // because they may be off the end or otherwise inaccurate.
  1892.     //
  1893.     // I'm not sure this (optimization) works - it still seems sluggish.
  1894.     
  1895.     if (cacheEngineGeneration != pDCLCompilerEngineData->engineGeneration)
  1896.     {
  1897.         cacheEngineGeneration = pDCLCompilerEngineData->engineGeneration;
  1898.         rangeLook = 0;
  1899.         pageLook = 0;
  1900.     }
  1901.     
  1902.     // Repeat until we find it or run out of places to look
  1903.     
  1904.     while ((lookCount < ioPrep->rangeInfo.multipleRanges.entryCount) && !pageCount)
  1905.     {
  1906.         try = &ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook];
  1907.         
  1908.         // pageCount is number of physAddr entries used by this range
  1909.         // either copy them (found) or skip over them (not found)
  1910.         
  1911.         pageCount = 1 + (((UInt32) try->base + try->length - 1) >> pageShift) -
  1912.                          ((UInt32) try->base >> pageShift);
  1913.                          
  1914.         // require exact match
  1915.         if ((void *) pBuffer == ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook].base)
  1916.         {
  1917.             // Found pages we want.  Copy page table.
  1918.             BlockMoveData(&ioPrep->physicalMapping[pageLook],
  1919.                           returnTable,
  1920.                           pageCount * sizeof (PhysicalAddress));
  1921.             pageLook += pageCount;
  1922.         }
  1923.         else
  1924.         {
  1925.             // These aren't the pages we're looking for.  Skip forward.
  1926.             pageLook += pageCount;
  1927.             pageCount = 0;
  1928.         }
  1929.         
  1930.         lookCount++;
  1931.         rangeLook++;
  1932.         if (rangeLook == ioPrep->rangeInfo.multipleRanges.entryCount)
  1933.         {
  1934.             rangeLook = 0;
  1935.             pageLook = 0;
  1936.         }
  1937.     }
  1938.     
  1939. //     if (!pageCount)
  1940. //         FWDebugStr ((ConstStr255Param) "\pFailed to find buffer!");
  1941.     
  1942.     return pageCount;
  1943. }
  1944.  
  1945.  
  1946. ////////////////////////////////////////////////////////////////////////////////
  1947. //
  1948. // AddReceivePacketDCL
  1949. //
  1950. // Add a receive packet DCL. Don't need to do anything. Any ReceivePacketDCL's
  1951. // already got processed by the preceding AddReceivePacketStartDCL routine.
  1952. //
  1953. //
  1954.  
  1955. static OSStatus AddReceivePacketDCL(
  1956.     DMABuildStatePtr            pDMABuildState,
  1957.     DCLCommandPtr                pDCLCommand)
  1958. {
  1959.     return noErr;
  1960. }
  1961.  
  1962.  
  1963. ////////////////////////////////////////////////////////////////////////////////
  1964. //
  1965. // AddTimeStampDCL
  1966. //
  1967. // Add a time stamp DCL.
  1968. //
  1969. // This DCL should already be handled by the send packet DCL processing routine.
  1970. //
  1971. // The DCL gets saved in a list of interrupt driven DCL's and the xfer
  1972. // status address of the DMA descriptor corresponding to the previous
  1973. // DCL also gets saved in the interrupt list. Upon interrupt the interrupt
  1974. // list gets scanned and checks the transfer status. If it is non-zero then
  1975. // the descriptor block has been completed and a needsInterruptProcessing
  1976. // bit is set along with posting a deferred task for later interrupt processing.
  1977. // 
  1978. // During the deferred task processing, the interrupt DCL's are scanned to
  1979. // check if they need processing. If they do, then they are processed, the
  1980. // xferStatus field is cleared, and then the needsInterruptProcessing flag
  1981. // is cleared.
  1982. //
  1983. // For this DCL the time stamp when the packet was sent is in the xferStatus
  1984. // field. Copy it into the DCL record at interrupt processing time.
  1985. //
  1986.  
  1987. static OSStatus AddTimeStampDCL(
  1988.     DMABuildStatePtr            pDMABuildState,
  1989.     DCLCommandPtr                pDCLCommand)
  1990. {
  1991.     // This should already be handled in the send packet start DCL routine.    
  1992.     return noErr;
  1993. }
  1994.  
  1995.  
  1996. ////////////////////////////////////////////////////////////////////////////////
  1997. //
  1998. // AddSendPacketStartDCL
  1999. //
  2000. // Add a send packet start DCL.
  2001. //
  2002.  
  2003. static OSStatus AddSendPacketStartDCL(
  2004.     DMABuildStatePtr            pDMABuildState,
  2005.     DCLCommandPtr                pDCLCommand,
  2006.     UInt32                        speed)
  2007. {
  2008.     FWIMDataPtr                    pFWIMData;
  2009.     DCLTransferPacketPtr        pDCLTransferPacket;
  2010.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  2011.     DCLCompilerDCLDataPtr        pInterruptDCLCompilerDCLData;
  2012.     UInt32                        packetSize, packetPageCount;
  2013.     PhysicalAddress                physTable[7];        // 7 is max
  2014.     UInt32                        sizeTable[7];
  2015.     UInt32                        pageSize, pageCount, pageIndex;
  2016.     UInt32                        branchAddress;
  2017.     DMADescriptorPtr            pDMA, pDoDMA;
  2018.     PhysicalAddress                pDMAPhys;
  2019.     UInt32                        startingInterruptCount;
  2020.     OSStatus                    status = noErr;
  2021.     Boolean                        needsInterrupt = false;
  2022.  
  2023.     // Recast DCL command.
  2024.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  2025.     pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLTransferPacket->compilerData;
  2026.     pFWIMData = pDMABuildState->pFWIMData;
  2027.  
  2028.     // Scan any SendPacketOp DCLs that follow this SendPacketStartOp DCL.
  2029.     // They will all combine with this one to send a single packet. Find out
  2030.     // all of the physical addresses and data sizes, including descriptor count.
  2031.     //
  2032.     // JKL *** What about zero size packets, this should all still work if
  2033.     // DataMapToPhysical returns a pageCount of 1 for a zero size packet.
  2034.     // If not only one descriptor would get allocate and two are needed.
  2035.     // The zero size packet case could get handled by a separate routine.
  2036.     
  2037.     packetSize = 0;
  2038.     packetPageCount = 0;
  2039.     pageSize = pFWIMData->pageSize;
  2040.     
  2041.     do
  2042.     {
  2043.         packetSize += pDCLTransferPacket->size;
  2044.         pageCount = DataMapToPhysical(pDMABuildState->pDCLCompilerEngineData,
  2045.                                       pDCLTransferPacket->buffer,
  2046.                                       pDCLTransferPacket->size,
  2047.                                       &physTable[packetPageCount]);
  2048.         
  2049.         for (pageIndex = 0; pageIndex < (pageCount - 1); pageIndex++, packetPageCount++) 
  2050.         {
  2051.             // determine reqCount for preliminary page(s)
  2052.             if (pageIndex == 0)
  2053.                 sizeTable[packetPageCount] = pageSize - ((UInt32) pDCLTransferPacket->buffer & (pageSize - 1));
  2054.             else
  2055.                 sizeTable[packetPageCount] = pageSize;
  2056.         }
  2057.  
  2058.         // determine reqCount for last page
  2059.         if (pageCount == 1)
  2060.             sizeTable[packetPageCount] = pDCLTransferPacket->size;
  2061.         else
  2062.             sizeTable[packetPageCount] = ((UInt32) pDCLTransferPacket->buffer + pDCLTransferPacket->size) & (pageSize - 1);
  2063.  
  2064.         packetPageCount++;
  2065.         
  2066.         pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
  2067.  
  2068.         if (pDCLTransferPacket != nil)
  2069.         {
  2070.             if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) != kDCLSendPacketOp)
  2071.             {
  2072.                 // look ahead to see if packet receipt needs to trigger interrupt
  2073.                 // save interrupt count since it gets updated in this routine
  2074.                 startingInterruptCount = pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum];
  2075.                 needsInterrupt = AddTransmitDCLInterrupt((DCLCommandPtr) pDCLTransferPacket, pFWIMData, pDMABuildState->dmaPortNum);
  2076.                     
  2077.                 pDCLTransferPacket = nil;
  2078.             }
  2079.         }
  2080.  
  2081.     } while (pDCLTransferPacket != nil);
  2082.     
  2083.     if (packetPageCount > 6)
  2084.     {
  2085.         status = -1;
  2086.         FWDebugStr("\pAddSendPacketStartDCL, too many descriptors");
  2087.     }
  2088.     
  2089.     if (status == noErr)
  2090.     {
  2091.         // Allocate new descriptor. Special case null packets.
  2092.         if (packetSize == 0)
  2093.             packetPageCount++;
  2094.         else
  2095.             packetPageCount += 2;
  2096.  
  2097.         status = AllocateDMA(pDMABuildState, &pDMA, &pDMAPhys, packetPageCount);
  2098.  
  2099.         pDoDMA = pDMA;
  2100.     }
  2101.     
  2102.     // fill out start descriptor
  2103.     if (status == noErr)
  2104.     {
  2105.         if (packetSize == 0)
  2106.         { // handle zero length packet
  2107.             // use output last immediate (uses 2 dma descriptors)
  2108.             pDoDMA->descriptorField[0] = EndianSwapImm32Bit( 8    |        // reqCount = 8 for immediate
  2109.                                             kOutputLastImmCmd << kDMACommandPhase |
  2110.                                             kOutputLastImmKey << kDMAKeyPhase |
  2111.                                             kOutputLastBranch << kDMABranchPhase);
  2112.             if (needsInterrupt)
  2113.             {
  2114.                 // set interrupt and update status bits
  2115.                 pDoDMA->descriptorField[0] |= EndianSwapImm32Bit(kInterruptAlways << kDMAInterruptPhase | kDMAInputStatus);
  2116.     
  2117.                 // save last DMA descriptor in interrupt DCL's data
  2118.                 // when interrupt comes in, check xfer status to see if descriptor completed, yuck
  2119.                 while (startingInterruptCount < pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum])
  2120.                 {
  2121.                     pDCLCommand = pFWIMData->pDCLInterruptList[pDMABuildState->dmaPortNum]
  2122.                                                               [startingInterruptCount].pDCLCommand;
  2123.                     pInterruptDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  2124.                     pInterruptDCLCompilerDCLData->pDMA = pDoDMA;
  2125.                     startingInterruptCount++;
  2126.                 }
  2127.             }
  2128.             pDoDMA->descriptorField[2] = 0; // branch address for later use
  2129.             pDoDMA->descriptorField[3] = 0; // status for later use
  2130.             
  2131.             // The next descriptor's address for branching goes here.
  2132.             branchAddress = (UInt32) &pDoDMA->descriptorField[2];
  2133.  
  2134.             // put header quads in second part of descriptor
  2135.             // JKl *** set speed, tag, synch bits
  2136.             pDoDMA++;
  2137.             pDoDMA->descriptorField[0] = EndianSwapImm32Bit(
  2138.                                             pDMABuildState->syncBits |
  2139.                                             kFWTCodeIsochronousBlock << kIsochTCodePhase |
  2140.                                             pDMABuildState->isochChannelNum << kIsochTxChannelPhase |
  2141.                                             pDMABuildState->tagBits << kIsochTagPhase |
  2142.                                             speed << kIsochTxSpeedPhase);
  2143.             pDoDMA->descriptorField[1] = 0;
  2144.         }
  2145.         else
  2146.         {
  2147.             // use output more immediate (uses 2 dma descriptors)
  2148.             pDoDMA->descriptorField[0] = EndianSwapImm32Bit(8 |        // reqCount 8 for immediate
  2149.                                             kOutputMoreImmCmd << kDMACommandPhase |
  2150.                                             kOutputMoreImmKey << kDMAKeyPhase);
  2151.  
  2152.             // Set skip address to resend same packet
  2153.             pDoDMA->descriptorField[2] = (UInt32) pDMAPhys + packetPageCount;
  2154.             
  2155.             // put header quads in second part of descriptor
  2156.             // JKl *** set speed, tag, synch bits
  2157.             pDoDMA++;
  2158.             pDoDMA->descriptorField[0] = EndianSwapImm32Bit(
  2159.                                             pDMABuildState->syncBits |
  2160.                                             kFWTCodeIsochronousBlock << kIsochTCodePhase |
  2161.                                             pDMABuildState->isochChannelNum << kIsochTxChannelPhase |
  2162.                                             pDMABuildState->tagBits << kIsochTagPhase |
  2163.                                             speed << kIsochTxSpeedPhase);
  2164.             // set packetSize
  2165.             pDoDMA->descriptorField[1] = EndianSwapImm32Bit(packetSize << kIsochTxDataLengthPhase);
  2166.  
  2167.             pDoDMA++;
  2168.         }
  2169.     }
  2170.     
  2171.     if ((status == noErr) && (packetSize > 0))
  2172.     {
  2173.         // fill in pereliminary OUTPUT_MORE descriptors, subtracting three from packetPageCount:
  2174.         // first two descriptors are for output_immediate and last one is for output_last
  2175.         for (pageIndex = 0; pageIndex < (packetPageCount - 3); pageIndex++)
  2176.         {
  2177.             pDoDMA->descriptorField[0] = EndianSwapImm32Bit(sizeTable[pageIndex]); // reqCount, rest 0
  2178.             pDoDMA->descriptorField[1] = EndianSwapImm32Bit((UInt32) physTable[pageIndex]);
  2179.             
  2180.             pDoDMA++;
  2181.         }
  2182.     
  2183.         // complete packet with OUTPUT_LAST descriptor
  2184.         pDoDMA->descriptorField[0] = EndianSwapImm32Bit (
  2185.                                         sizeTable[pageIndex] |            // reqCount
  2186.                                         kOutputLastBranch << kDMABranchPhase |
  2187.                                         kOutputLastCmd << kDMACommandPhase);
  2188.         if (needsInterrupt)
  2189.         {
  2190.             // set interrupt and update status bits
  2191.             pDoDMA->descriptorField[0] |= EndianSwapImm32Bit(kInterruptAlways << kDMAInterruptPhase | kDMAInputStatus);
  2192.  
  2193.             // save DMA descriptor address in DCLInterrupt record
  2194.             // when interrupt comes in, check xfer status to see if descriptor completed, yuck
  2195.             while (startingInterruptCount < pFWIMData->numDCLInterrupts[pDMABuildState->dmaPortNum])
  2196.             {
  2197.                 pDCLCommand = pFWIMData->pDCLInterruptList[pDMABuildState->dmaPortNum]
  2198.                                                           [startingInterruptCount].pDCLCommand;
  2199.                 pInterruptDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  2200.                 pInterruptDCLCompilerDCLData->pDMA = pDoDMA;
  2201.                 startingInterruptCount++;
  2202.             }
  2203.         }
  2204.         pDoDMA->descriptorField[1] = EndianSwapImm32Bit((UInt32) physTable[pageIndex]);
  2205.         pDoDMA->descriptorField[2] = 0;  // used later for branch address
  2206.         pDoDMA->descriptorField[3] = 0;  // used later for transfer status
  2207.  
  2208.         // The next descriptor's address for branching goes here.
  2209.         branchAddress = (UInt32) &pDoDMA->descriptorField[2];
  2210.     }
  2211.     
  2212.     // Link previous descriptor and add Z value
  2213.     if (status == noErr)
  2214.     {
  2215.         if (pDMABuildState->pLastBranch)
  2216.             *(pDMABuildState->pLastBranch) = EndianSwapImm32Bit((UInt32) pDMAPhys + packetPageCount);
  2217.     }
  2218.  
  2219.     // Store the address for the next descriptor's start
  2220.     if (status == noErr)
  2221.         pDMABuildState->pLastBranch = (UInt32 *) branchAddress;
  2222.  
  2223.     // Initialize start DMA if not already set. Add Z value to address.
  2224.     if ((status == noErr) && (pDMABuildState->pDCLCompilerEngineData->pStartDMA == nil))
  2225.         pDMABuildState->pDCLCompilerEngineData->pStartDMA = (UInt32) pDMAPhys + packetPageCount;
  2226.  
  2227.     // Store results in DCL transfer packet record.
  2228.     //zzz should fill in CompilerDCLData for SendPacketOps we compiled.
  2229.     // but I don't think it ever gets used, unless we update buffers (NYI anyway)
  2230.     // Add Z value to DMAPhys for label/jump use. Mask 4 Z value bits if physical
  2231.     // address if needed.
  2232.     if (status == noErr)
  2233.     {
  2234.         pDCLCompilerDCLData->pDMA = pDMA;
  2235.         pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) ((UInt32) pDMAPhys + packetPageCount);
  2236.     }
  2237.     else
  2238.     {
  2239.         pDCLCompilerDCLData->pDMA = nil;
  2240.         pDCLCompilerDCLData->pDMAPhys = nil;
  2241.     }
  2242.  
  2243.     return status;
  2244. }
  2245.  
  2246.  
  2247. ////////////////////////////////////////////////////////////////////////////////
  2248. //
  2249. // AddSendPacketWithHeaderStartDCL
  2250. //
  2251. // Adds a send packet with header start DCL.
  2252. //zzz need to be able to specify speed.
  2253. //
  2254.  
  2255. static OSStatus AddSendPacketWithHeaderStartDCL(
  2256.     DMABuildStatePtr            pDMABuildState,
  2257.     DCLCommandPtr                pDCLCommand,
  2258.     UInt32                        speed)
  2259. {
  2260. // JKL *** Similar SendPacketStart with the addition of adding the header
  2261. // to the descriptor and possibly changing transmit context settings.
  2262.  
  2263.     FWDebugStr ("\pAddSendPacketWithHeaderStartDCL, not yet implemented");
  2264.     return -1;
  2265. }
  2266.  
  2267.  
  2268. ////////////////////////////////////////////////////////////////////////////////
  2269. //
  2270. // AddTransmitDCLInterrupt
  2271. //
  2272. // Look ahead at DCL commands to see if any interrupt opcodes follow a transmit
  2273. // DCL. Add them to the interrupt list. The transmit DCL processor will then
  2274. // add additional information to the new interrupt records.
  2275. //
  2276. static Boolean AddTransmitDCLInterrupt (
  2277.     DCLCommandPtr                pDCLCommand,
  2278.     FWIMDataPtr                    pFWIMData,
  2279.     UInt32                        portNum)
  2280. {
  2281.     UInt32                        opcode;
  2282.     DCLProgramInterruptPtr        pDCLInterrupt;
  2283.     Boolean                        foundInterruptDCL = false;
  2284.     
  2285.     while (pDCLCommand != nil)
  2286.     {
  2287.         opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  2288.         
  2289.         switch (opcode)
  2290.         {
  2291.             case kDCLCallProcOp:
  2292.             case kDCLUpdateDCLListOp:
  2293.             case kDCLTimeStampOp:
  2294.                 if (pFWIMData->numDCLInterrupts[portNum] < kNumDCLInterrupts)
  2295.                 {
  2296.                     foundInterruptDCL = true;
  2297.                     pDCLInterrupt = &pFWIMData->pDCLInterruptList[portNum][pFWIMData->numDCLInterrupts[portNum]];
  2298.                     pDCLInterrupt->pDCLCommand = pDCLCommand;
  2299.                     pDCLInterrupt->pendingInterrupt = false;
  2300.                     pFWIMData->numDCLInterrupts[portNum]++;
  2301.                     pDCLCommand = pDCLCommand->pNextDCLCommand;
  2302.                 }
  2303.                 else
  2304.                 {
  2305.                     pDCLCommand = nil;
  2306.                     FWDebugStr("\pAddTransmitDCLInterrupt, need more DCLProgramInterrupt records");
  2307.                 }
  2308.                 
  2309.                 break;
  2310.                 
  2311.             case kDCLLabelOp:    // skip over any label or jumps continuing looking for interrupt Ops
  2312.             case kDCLJumpOp:
  2313.                     pDCLCommand = pDCLCommand->pNextDCLCommand;
  2314.                 break;
  2315.                 
  2316.             default:
  2317.                 pDCLCommand = nil;
  2318.         }
  2319.     }
  2320.     return foundInterruptDCL;
  2321. }
  2322.  
  2323.  
  2324. ////////////////////////////////////////////////////////////////////////////////
  2325. //
  2326. // AddSendPacketDCL
  2327. //
  2328. // Add a send packet DCL.
  2329. //
  2330. // There's nothing to do here, since the portion of the packet described by
  2331. // this DCL is already processed in the preceeding SendPacketStartOp.
  2332.  
  2333. static OSStatus AddSendPacketDCL(
  2334.     DMABuildStatePtr            pDMABuildState,
  2335.     DCLCommandPtr                pDCLCommand)
  2336. {
  2337.     return noErr;
  2338. }
  2339.  
  2340.  
  2341. ////////////////////////////////////////////////////////////////////////////////
  2342. //
  2343. // AddCallProcDCL
  2344. //
  2345. // Add a call proc DCL.
  2346. //
  2347. // This DCL should already be handled by the packet DCL processing routines.
  2348. //
  2349. // The DCL gets saved in a list of interrupt driven DCL's. The xferStatus
  2350. // address of the DMA descriptor corresponding to the previous DCL
  2351. // also gets saved in the interrupt list. Upon interrupt the interrupt
  2352. // list gets scanned and checks the transfer status. If it is non-zero then
  2353. // the descriptor block has been completed and a needsInterruptProcessing
  2354. // bit is set along with posting a deferred task for later interrupt processing.
  2355. // 
  2356. // During the deferred task processing, the interrupt DCL's are scanned to
  2357. // check if they need processing. If they do, then they are processed, the
  2358. // xferStatus field is cleared, and then the needsInterruptProcessing flag
  2359. // is cleared.
  2360. //
  2361. // For this DCL the callProc will be called through FireWire services.
  2362. //
  2363. // This would not work if someone wanted to place a CallProc at the beginning of
  2364. // the DCL, would anyone want to do that? JKL ****
  2365. //
  2366.  
  2367. static OSStatus AddCallProcDCL(
  2368.     DMABuildStatePtr            pDMABuildState,
  2369.     DCLCommandPtr                pDCLCommand)
  2370. {
  2371.     // This should already be handled in the packet start DCL routines.    
  2372.     return noErr;
  2373. }
  2374.  
  2375.  
  2376. ////////////////////////////////////////////////////////////////////////////////
  2377. //
  2378. // UpdateDCLListDCL
  2379. //
  2380. // Add a update DCL list DCL. Same description as routine above.
  2381. //
  2382.  
  2383. static OSStatus AddUpdateDCLListDCL(
  2384.     DMABuildStatePtr            pDMABuildState,
  2385.     DCLCommandPtr                pDCLCommand)
  2386. {
  2387.     // This should already be handled in the packet start DCL routines.    
  2388.     return noErr;
  2389. }
  2390.  
  2391.  
  2392. ////////////////////////////////////////////////////////////////////////////////
  2393. //
  2394. // AddJumpAddress
  2395. //
  2396. // Add the preceding DMA's branch address field to the jump DCL data.
  2397. //
  2398.  
  2399. static OSStatus AddJumpAddress(
  2400.     DMABuildStatePtr            pDMABuildState,
  2401.     DCLCommandPtr                pDCLCommand)
  2402. {
  2403.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  2404.     DCLJumpPtr                    pDCLJump;
  2405.     OSStatus                    status = noErr;
  2406.     
  2407.     // recast DCL command
  2408.     pDCLJump = (DCLJumpPtr) pDCLCommand;
  2409.     pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLJump->compilerData;
  2410.     
  2411.     // store the address for the branch field in the dmaPhys field
  2412.     pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) pDMABuildState->pLastBranch;
  2413.  
  2414.     return status;
  2415. }
  2416.  
  2417.  
  2418. ////////////////////////////////////////////////////////////////////////////////
  2419. //
  2420. // ProcessJumpDCL
  2421. //
  2422. // Process a jump DCL.
  2423. //
  2424. // The jump DCL has the address of the branch field filled in during packet
  2425. // DCL processing. Update the branch field with the address stashed
  2426. // in the corresponding label field. That address has Z value stored in it.
  2427. //
  2428.  
  2429. static OSStatus ProcessJumpDCL(
  2430.     DCLJumpPtr                    pDCLJump)
  2431. {
  2432.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  2433.     DCLCompilerDCLDataPtr        pLabelDCLCompilerDCLData;
  2434.     DCLLabelPtr                    pDCLLabel;
  2435.     OSStatus                    status = noErr;
  2436.     
  2437.     // get DCL command compiler data
  2438.     pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLJump->compilerData;
  2439.     
  2440.     // get label record
  2441.     pDCLLabel = (DCLLabelPtr) pDCLJump->pJumpDCLLabel;
  2442.     pLabelDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLLabel->compilerData;
  2443.     
  2444.     if (pDCLCompilerDCLData->pDMAPhys != nil)
  2445.         *((UInt32 *) pDCLCompilerDCLData->pDMAPhys) = EndianSwapImm32Bit((UInt32) pLabelDCLCompilerDCLData->pDMAPhys);
  2446.  
  2447.     return status;
  2448. }
  2449.  
  2450.  
  2451. ////////////////////////////////////////////////////////////////////////////////
  2452. //
  2453. // ProcessLabelDCL
  2454. //
  2455. // Add a label DCL.
  2456. //
  2457. // Look ahead to the next packet DCL and store its physical DMA address for
  2458. // a jump instruction to use as a branch.
  2459. //
  2460. // JKL *** Some label DCL ops may come at the end of a DCL program with no Send/
  2461. // Receive PacketStarts following it. In that case what to do, since the process
  2462. // has been to key the label off of the next Send/Receive PacketStart?
  2463. //
  2464. // For isoch transmit create an output_last descriptor indicating no packet is to
  2465. // be sent for the current cycle. Attach the label to that descriptor. Normally there
  2466. // is also interrupt requests following this label, such as update or callProc. They
  2467. // get keyed off the previous Send/Receive PacketStart not this new dummy descriptor.
  2468. // The DCL program might want to jump to that label from somewhere else and execute
  2469. // the interrupt driven ops. This won't happen in this case since the interrupt is
  2470. // not keyed off this dummy descriptor.
  2471. //
  2472. // For isoch receive when there is a label at the end of a program, attach this label
  2473. // back to the first ReceivePacketStart DCL in the program. Again you can run into
  2474. // the same problem described above where the intention may be to execute some update
  2475. // or callProc after the label, but that does not happen since the interrupt needed to
  2476. // make that execution happen is keyed off of the previous ReceivePacket op.
  2477. //
  2478.  
  2479. static OSStatus ProcessLabelDCL(
  2480.     DMABuildStatePtr            pDMABuildState,
  2481.     DCLLabelPtr                    pDCLLabel,
  2482.     Boolean                        talking)
  2483. {
  2484.     DCLCommandPtr                pDCLCommand;
  2485.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData,
  2486.                                 pNextDCLCompilerDCLData;
  2487.     DMADescriptorPtr            pDMA;
  2488.     PhysicalAddress                pDMAPhys;
  2489.     UInt32                        opcode;
  2490.     OSStatus                    status = noErr;
  2491.  
  2492.     // get DCL command compiler data
  2493.     pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLLabel->compilerData;
  2494.     
  2495.     // look at next DCL
  2496.     pDCLCommand = pDCLLabel->pNextDCLCommand;
  2497.     opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  2498.     
  2499.     // skip over any DCL's until the next Send or Receive packet startOp is found
  2500.     while ((pDCLCommand != nil) && (opcode != kDCLSendPacketStartOp) && (opcode != kDCLReceivePacketStartOp))
  2501.     {
  2502.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  2503.         opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  2504.     }
  2505.     
  2506.     // JKL *** this only works for isoch transmit and creates a descriptor to indicate
  2507.     // no packet shold be sent for the current cycle. I think this is OK since if you ever
  2508.     // get to this descriptor, things may be in bad shape.
  2509.     if ((pDCLCommand == nil) && talking)
  2510.     {
  2511.         // create a single output_last descriptor so the jump has an address/label to jump to
  2512.         status = AllocateDMA(pDMABuildState, &pDMA, &pDMAPhys, 1);
  2513.         if (status == noErr)
  2514.         {
  2515.             pDMA->descriptorField[0] = EndianSwapImm32Bit(0 |
  2516.                                             kOutputLastCmd << kDMACommandPhase |
  2517.                                             kOutputLastKey << kDMAKeyPhase |
  2518.                                             kOutputLastBranch << kDMABranchPhase);
  2519.             pDMA->descriptorField[2] = 0;
  2520.             pDMA->descriptorField[3] = 0;
  2521.  
  2522.             // update branch address and value
  2523.             if (pDMABuildState->pLastBranch)
  2524.                 *(pDMABuildState->pLastBranch) = EndianSwapImm32Bit((UInt32) pDMAPhys + 1);
  2525.             
  2526.             pDMABuildState->pLastBranch = (UInt32 *) &pDMA->descriptorField[2];
  2527.         }
  2528.     }
  2529.     
  2530.     if (pDCLCommand != nil)
  2531.     {
  2532.         pNextDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  2533.         
  2534.         // JKL *** Could DMAPhys be nil?
  2535.         pDCLCompilerDCLData->pDMAPhys = pNextDCLCompilerDCLData->pDMAPhys;
  2536.     }
  2537.     else
  2538.     {
  2539.         if (talking)
  2540.             // point label to new dummy descriptor
  2541.             pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) ((UInt32) pDMAPhys + 1);
  2542.         else
  2543.             // label is at end of DMA program, loop back to start
  2544.             pDCLCompilerDCLData->pDMAPhys = (PhysicalAddress) pDMABuildState->pDCLCompilerEngineData->pStartDMA;
  2545.     }
  2546.     
  2547.     return status;
  2548. }
  2549.  
  2550.  
  2551. ////////////////////////////////////////////////////////////////////////////////
  2552. //
  2553. // AddSetTagSyncBitsDCL
  2554. //
  2555. // Add a set tag and sync bits DCL. Store the values in DMA build record for
  2556. // all future descriptor processing.
  2557. //
  2558. // JKL *** Will those include following execution (jumps) properly.
  2559. //
  2560.  
  2561. static OSStatus AddSetTagSyncBitsDCL(
  2562.     DMABuildStatePtr            pDMABuildState,
  2563.     DCLCommandPtr                pDCLCommand)
  2564. {
  2565.     DCLSetTagSyncBitsPtr        pDCLSetTagSyncBits;
  2566.     OSStatus                    status = noErr;
  2567.  
  2568.     // Recast DCL command, get data.
  2569.     pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) pDCLCommand;
  2570.  
  2571.     // set values in DMABuild record
  2572.     pDMABuildState->tagBits = pDCLSetTagSyncBits->tagBits;
  2573.     pDMABuildState->syncBits = pDCLSetTagSyncBits->syncBits;
  2574.  
  2575.     return status;
  2576. }
  2577.  
  2578.  
  2579. ////////////////////////////////////////////////////////////////////////////////
  2580. //
  2581. // UpdateDCLTimeStamp
  2582. //
  2583. // Update a DCL time stamp.  It reads the time stamp out of a DMA descriptor
  2584. // and writes it into the timeStamp field of the DCL.
  2585. //
  2586.  
  2587. static OSStatus UpdateDCLTimeStamp(
  2588.     DCLTimeStampPtr                pDCLTimeStamp)
  2589. {
  2590.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  2591.     UInt32                        timeStamp;
  2592.     OSStatus                    status = noErr;
  2593.  
  2594.     // Get DCL compiler data.
  2595.     pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLTimeStamp->compilerData;
  2596.  
  2597.     // Copy time stamp from saved status/timeStamp descriptor field.
  2598.     // Xfer status has 3 second bits and 12 cycle count bits, shift to match cycle count register.
  2599.     // JKL *** should the rest of the seconds bits be or'd in from the cycle count, checking for
  2600.     // an overflow that would need to increment the first three seconds bits. Otherwise hopefully
  2601.     // the high four bits of seconds would not have changed by the time this is executed. 
  2602.     timeStamp = EndianSwapImm32Bit(pDCLCompilerDCLData->pDMA->descriptorField[3]) & kDMATimeStamp;
  2603.     pDCLTimeStamp->timeStamp = timeStamp << 12;
  2604.  
  2605.     return status;
  2606. }
  2607.  
  2608.  
  2609. ////////////////////////////////////////////////////////////////////////////////
  2610. //
  2611. // UpdateDCLReceivePacketStart
  2612. //
  2613. // Update DCL receive packet start. Byte swap the packet header.
  2614. //
  2615.  
  2616. static OSStatus UpdateDCLReceivePacketStart(
  2617.     DCLTransferPacketPtr        pDCLTransferPacket)
  2618. {
  2619.     UInt32                        packetHeader;
  2620.     OSStatus                    status = noErr;
  2621.  
  2622.     // Byte swap the header
  2623.     packetHeader = *((UInt32 *) pDCLTransferPacket->buffer);
  2624.     *((UInt32 *) pDCLTransferPacket->buffer) = EndianSwapImm32Bit(packetHeader);
  2625.     
  2626.     return status;
  2627. }
  2628.  
  2629.  
  2630. ////////////////////////////////////////////////////////////////////////////////
  2631. //
  2632. // HandleIsochRxInterrupt
  2633. //
  2634. // Handle isoch receive interrupts.
  2635. //
  2636. // Scan the DCL interrupt list and update needsInterrupt field for each.
  2637. // Schedule deferred task.
  2638. //
  2639. // JKL *** Is this too much processing for interruptPending time? Time it.
  2640. // *** portNum needs to be available for multiple contexts,
  2641. // maybe use context numbers somehow
  2642. //
  2643.  
  2644. void HandleIsochRxInterrupt(
  2645.     FWIMDataPtr                    pFWIMData)
  2646. {
  2647.     DCLCommandPtr                pDCLCommand;
  2648.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  2649.     OHCIRegistersPtr            pOHCIRegs;
  2650.     UInt32                        interruptStatus, interruptStatusLittleEndian;
  2651.     UInt32                        interruptDCLIndex;
  2652.     UInt32                        portNum;
  2653.     OSStatus                    status = noErr;
  2654.  
  2655.     // Get our register base address.
  2656.     pOHCIRegs = pFWIMData->pOHCIRegisters;
  2657.  
  2658.     // Read separate isoch receive interrupt status register to determine context that
  2659.     // interrupt is for. intEventClear reads the masked version of interrupt status
  2660.     // intEventSet reads the interrupt status without mask. Not used.
  2661.     interruptStatusLittleEndian = pOHCIRegs->isochRxIntEventClear;
  2662.     interruptStatus = EndianSwapImm32Bit(interruptStatusLittleEndian);
  2663.  
  2664.     portNum = kIsochReceivePort;
  2665.     
  2666.     // scan DCL interrupt list looking for DCL's that have completed
  2667.     for (interruptDCLIndex = 0; interruptDCLIndex < pFWIMData->numDCLInterrupts[portNum]; interruptDCLIndex++)
  2668.     {
  2669.         pDCLCommand = pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pDCLCommand;
  2670.         pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  2671.         if (EndianSwapImm32Bit(pDCLCompilerDCLData->pDMA->descriptorField[3]) & kDMATransferStatus)
  2672.             pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt = true;
  2673.     }
  2674.     
  2675.     if (!pFWIMData->isochReceiveDTScheduled)
  2676.     {
  2677.         status = FWScheduleDeferredTask(pFWIMData->isochReceiveDeferredTaskID, nil);
  2678.  
  2679.         if (status == noErr)
  2680.             pFWIMData->isochReceiveDTScheduled = true;
  2681.     }
  2682.  
  2683.     pOHCIRegs->isochRxIntEventClear = interruptStatusLittleEndian;
  2684.     SynchronizeIO();
  2685. }
  2686.  
  2687.  
  2688. ////////////////////////////////////////////////////////////////////////////////
  2689. //
  2690. // HandleIsochTxInterrupt
  2691. //
  2692. // Handle isoch transmit interrupts.
  2693. //
  2694. // Scan the DCL interrupt list and update interruptPending field for each.
  2695. // Schedule deferred task.
  2696. //
  2697. // JKL *** Is this too much processing for interrupt time? Time it.
  2698. // *** portNum needs to be available for multiple contexts,
  2699. // maybe use context numbers somehow
  2700. //
  2701.  
  2702. void HandleIsochTxInterrupt(
  2703.     FWIMDataPtr                    pFWIMData)
  2704. {
  2705.     DCLCommandPtr                pDCLCommand;
  2706.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  2707.     OHCIRegistersPtr            pOHCIRegs;
  2708.     UInt32                        interruptStatus, interruptStatusLittleEndian;
  2709.     UInt32                        interruptDCLIndex;
  2710.     UInt32                        portNum;
  2711.     OSStatus                    status = noErr;
  2712.  
  2713.     // Get our register base address.
  2714.     pOHCIRegs = pFWIMData->pOHCIRegisters;
  2715.  
  2716.     // Read separate isoch receive interrupt status register to determine context that
  2717.     // interrupt is for. intEventClear reads the masked version of interrupt status
  2718.     // intEventSet reads the interrupt status without mask. Not used.
  2719.     interruptStatusLittleEndian = pOHCIRegs->isochTxIntEventClear;
  2720.     interruptStatus = EndianSwapImm32Bit(interruptStatusLittleEndian);
  2721.  
  2722.     portNum = kIsochTransmitPort;
  2723.     
  2724.     // scan DCL interrupt list looking for DCL's that have completed
  2725.     for (interruptDCLIndex = 0; interruptDCLIndex < pFWIMData->numDCLInterrupts[portNum]; interruptDCLIndex++)
  2726.     {
  2727.         pDCLCommand = pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pDCLCommand;
  2728.         pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  2729.         if (pDCLCompilerDCLData->pDMA->descriptorField[3])
  2730.             pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt = true;
  2731.     }
  2732.     
  2733.     if (!pFWIMData->isochTransmitDTScheduled)
  2734.     {
  2735.         status = FWScheduleDeferredTask(pFWIMData->isochTransmitDeferredTaskID, nil);
  2736.  
  2737.         if (status == noErr)
  2738.             pFWIMData->isochTransmitDTScheduled = true;
  2739.     }
  2740.  
  2741.     pOHCIRegs->isochTxIntEventClear = interruptStatusLittleEndian;
  2742.     SynchronizeIO();
  2743. }
  2744.  
  2745.  
  2746. ////////////////////////////////////////////////////////////////////////////////
  2747. //
  2748. // IsochReceiveDeferredTask
  2749. //
  2750. // Handle DMA interrupts for isochronous receive.
  2751. //
  2752.  
  2753. void IsochReceiveDeferredTask(
  2754.     void                        *p1,
  2755.     void                        *p2)
  2756. {
  2757.     FWIMDataPtr                    pFWIMData = (FWIMDataPtr) p1;
  2758.     OHCIRegistersPtr            pOHCIRegs = pFWIMData->pOHCIRegisters;
  2759.     IsochPortDataPtr            pIsochPortData;
  2760.     DCLCommandPtr                pDCLCommand;
  2761.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  2762.     DCLCallProcPtr                pDCLCallProc;
  2763.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  2764.     UInt32                        interruptDCLIndex;
  2765.     UInt32                        portNum;
  2766.     OSStatus                    status = noErr;
  2767.  
  2768.     // Isoch receive DT no longer scheduled.
  2769.     pFWIMData->isochReceiveDTScheduled = false;
  2770.  
  2771.     if (pOHCIRegs->isochRxContext[kIRContext0].controlSet & EndianSwapImm32Bit(kDMADead))
  2772.     {
  2773.         status = -1;
  2774.         sprintf(debugStr, "IR context dead, status = 0x%08lx", EndianSwap32Bit(pOHCIRegs->isochRxContext[kIRContext0].controlSet));
  2775.         FWDebugStr((ConstStr255Param) c2pstr(debugStr));
  2776.     }
  2777.     
  2778.     if (status == noErr)
  2779.     {
  2780.         // Get isoch port data.
  2781.         // JKL *** need to be able to get portNum when using multiple contexts
  2782.         portNum = kIsochReceivePort;
  2783.         pIsochPortData = pFWIMData->isochPortDataList[portNum];
  2784.     
  2785.         // Run through DCL interrupt list looking for DCL's that need processing.
  2786.         for (interruptDCLIndex = 0; interruptDCLIndex < pFWIMData->numDCLInterrupts[portNum]; interruptDCLIndex++)
  2787.         {
  2788.             if (pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt)
  2789.             {
  2790.                 pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt = false;
  2791.                 pDCLCommand = pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pDCLCommand;
  2792.         
  2793.                 // Dispatch off of opcode.
  2794.                 switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  2795.                 {
  2796.                     case kDCLCallProcOp :
  2797.                         // Call the proc.
  2798.                         pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  2799.                         FWCallDCLCallProc(pIsochPortData->dclProgramID, pDCLCallProc);
  2800.                         break;
  2801.         
  2802.                     case kDCLUpdateDCLListOp :
  2803.                         // Update the DCL list.
  2804.                         pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  2805.                         DCLCompilerUpdateNotification(pIsochPortData->dclProgramID,
  2806.                                                       pDCLUpdateDCLList->dclCommandList,
  2807.                                                       pDCLUpdateDCLList->numDCLCommands);
  2808.                         break;
  2809.         
  2810.                     default :
  2811.                         break;
  2812.                 }
  2813.             
  2814.                 // clear xfer status field to note interrupt handled
  2815.                 // JKL *** OK to clear resCount field here?
  2816.                 pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  2817.                 pDCLCompilerDCLData->pDMA->descriptorField[3] = 0;
  2818.             }
  2819.         }
  2820.     }
  2821. }
  2822.  
  2823.  
  2824. ////////////////////////////////////////////////////////////////////////////////
  2825. //
  2826. // IsochTransmitDeferredTask
  2827. //
  2828. // Handle DMA interrupts for isochronous transmit.
  2829. //
  2830.  
  2831. void IsochTransmitDeferredTask(
  2832.     void                        *p1,
  2833.     void                        *p2)
  2834. {
  2835.     FWIMDataPtr                    pFWIMData = (FWIMDataPtr) p1;
  2836.     IsochPortDataPtr            pIsochPortData;
  2837.     DCLCommandPtr                pDCLCommand;
  2838.     DCLCompilerDCLDataPtr        pDCLCompilerDCLData;
  2839.     DCLCallProcPtr                pDCLCallProc;
  2840.     DCLTimeStampPtr                pDCLTimeStamp;
  2841.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  2842.     UInt32                        interruptDCLIndex;
  2843.     UInt32                        portNum;
  2844.     OSStatus                    status = noErr;
  2845.  
  2846.     // Isoch transmit DT no longer scheduled.
  2847.     pFWIMData->isochTransmitDTScheduled = false;
  2848.  
  2849.     // Get isoch port data.
  2850.     // JKL *** need to be able to get portNum when using multiple contexts
  2851.     portNum = kIsochTransmitPort;
  2852.     pIsochPortData = pFWIMData->isochPortDataList[portNum];
  2853.  
  2854.     for (interruptDCLIndex = 0; interruptDCLIndex < pFWIMData->numDCLInterrupts[portNum]; interruptDCLIndex++)
  2855.     {
  2856.         if (pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt)
  2857.         {
  2858.             pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pendingInterrupt = false;
  2859.             pDCLCommand = pFWIMData->pDCLInterruptList[portNum][interruptDCLIndex].pDCLCommand;
  2860.  
  2861.             // Dispatch off of opcode.
  2862.             switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  2863.             {
  2864.                 case kDCLCallProcOp :
  2865.                     // Call the proc.
  2866.                     pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  2867.                     FWCallDCLCallProc(pIsochPortData->dclProgramID, pDCLCallProc);
  2868.                     break;
  2869.     
  2870.                 case kDCLTimeStampOp :
  2871.                     // Update the time stamp.
  2872.                     pDCLTimeStamp = (DCLTimeStampPtr) pDCLCommand;
  2873.                     UpdateDCLTimeStamp(pDCLTimeStamp);
  2874.                     break;
  2875.     
  2876.                 case kDCLUpdateDCLListOp :
  2877.                     // Update the DCL list.
  2878.                     pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  2879.                     DCLCompilerUpdateNotification(pIsochPortData->dclProgramID,
  2880.                                                   pDCLUpdateDCLList->dclCommandList,
  2881.                                                   pDCLUpdateDCLList->numDCLCommands);
  2882.                     break;
  2883.     
  2884.                 default :
  2885.                     break;
  2886.             }
  2887.  
  2888.             // clear xfer status field to note interrupt handled
  2889.             pDCLCompilerDCLData = (DCLCompilerDCLDataPtr) pDCLCommand->compilerData;
  2890.             pDCLCompilerDCLData->pDMA->descriptorField[3] = 0;
  2891.         }
  2892.     }
  2893. }
  2894.